Reputation: 199
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
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
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