confused
confused

Reputation: 199

Bind Dragging of DIV element attributes to object properties in knockoutjs

I have here an object that will represent the div element

function ElementVM
{
    var self = this;

    self.Height = ko.observable();
    self.Width = ko.observable();
    self.Bottom = ko.observable();
}

and bind this to

<div data-bind="style:{ height: Height, width: Width, bottom: Bottom, position: 'absolute' }">

but the problem is, once this div element is dragged, for I've made it draggable, it won't changed the values of my ElementVM object.

Do you have any idea on how should binding works for this?

Thank you.

Upvotes: 0

Views: 528

Answers (2)

JotaBe
JotaBe

Reputation: 39004

To do this you need to use custom bindings. You can see it below, or in this jsfiddle.

// http://knockoutjs.com/documentation/custom-bindings.html
ko.bindingHandlers.draggable = {
     init : function(element, valueAccessor, allBindings, viewModel, bindingContext) {
        // This will be called when the binding is first applied to an element
        // Set up any initial state, event handlers, etc. here
        var $element = $(element);
        var position = ko.unwrap(valueAccessor());
        if (position) {
            if (position.left) 
                $element.css({left:ko.unwrap(position.left)});
            if (position.top) 
                $element.css({top:ko.unwrap(position.top)});
            if (position.height) 
                $element.height(ko.unwrap(position.height));
            if (position.width) 
                $element.width(ko.unwrap(position.width));
        }
        var draggable = $element.draggable({
            stop: function(event,ui) {
                if (position) {
                    if (ko.isWritableObservable(position.left))
                       position.left(ui.position.left);
                    if (ko.isWritableObservable(position.top))
                       position.top(ui.position.top);
                    if (ko.isWritableObservable(position.height))
                       position.height($element.height());
                    if (ko.isWritableObservable(position.width))
                       position.width($element.width());
                }
            }
        });
    },
    update : function(element, valueAccessor, allBindings, viewModel, bindingContext) {
        // This will be called once when the binding is first applied to an element,
        // and again whenever any observables/computeds that are accessed change
        // Update the DOM element based on the supplied values here.
        var position = ko.unwrap(valueAccessor());
        var $element = $(element);
        if (position.left)
			$element.css({left:ko.unwrap(position.left)+'px'});
        if (position.top)
			$element.css({top:ko.unwrap(position.top)+'px'});
        if (position.height)
            $element.height(ko.unwrap(position.height));
        if (position.width)
            $element.width(ko.unwrap(position.width));
    }
};

var vm = {
    position: ko.observable({
    	left: ko.observable(150),
    	top: ko.observable(125),
    	width: ko.observable(100),
    	height: ko.observable(40)
    })
};

ko.applyBindings(vm);
div {
    border: solid 1px #444;
    background-color: #DDD;
    text-align: center;
    padding: 12px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.11.4/jquery-ui.js"></script>  
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>

<div data-bind="draggable: position"
     style="position:absolute;">
    This is a draggable div
</div>
<ul>
    <li>Top: <input type="textbox" data-bind="value: position().top"/></li>
    <li>Left: <input type="textbox" data-bind="value: position().left"/></li>
    <li>Width: <input type="textbox" data-bind="value: position().width"/></li>
    <li>Height: <input type="textbox" data-bind="value: position().height"/></li>
</ul>
<pre data-bind="text:JSON.stringify(ko.toJS($root),null,2)"></pre>

Upvotes: 1

TSV
TSV

Reputation: 7641

Knockout "style" binding is a "one-way" binding: it looks for changes in the model and apply them to view (HTML element in this case).

If you want to set model values from HTML element you should do it by your code, which be subscribed on window.resize event or get HTML size by timer.

You can implement such a functionality via a custom binding or a component.

Upvotes: 0

Related Questions