0

I am using knockout.js. I created a view model say testViewModel with only 1 observable property testProperty.

function testViewModel()
{
  var self = this;

  self.testProperty = ko.observable("Initial");

}

than i created a span in which the changed value of testProperty is reflected and a input text field by which we can change the testProperty value.

 <span data-bind="text: testProperty"></span><br />
 <input type="text" data-bind="value: testProperty" />

I created an Example Fiddle.It seems that the observable property value is updated when the focusout event is executed on the input text field.

Now my question is that can we change the observable property value update event from focusout to something else. I created a save button also. Is there any way to update the observable property value only on save button press.

I am trying to create an application in which a user can create and save its profile and can edit the saved profile.I am using the same observable properties in create and edit form and these properties are observable. So when user edit its profile the ui should not be updated until user press the save button. This is my goal. Please help me to solve this issue ?

Tom Rider
  • 2,747
  • 7
  • 42
  • 65

3 Answers3

4

I would suggest have testProperty and testProperty_temp. Bind the input to temp and when the button is clicked, set testProperty to the testProperty_temp

function testViewModel()
{
   var self = this;

   self.testProperty = ko.observable("Initial");
   self.testProperty_temp = ko.obserable("");
   self.save = function() { self.testProperty(self.testProperty_temp()); }
 }

Hope this helps

Matthew
  • 411
  • 4
  • 14
  • thanks for reply but i have lots of properties, so is this a good practice to double the properties count ( means create a copy of each property ) ? – Tom Rider Oct 19 '12 at 18:56
2

Another means, along the same lines of what Matt Burland suggested:

http://jsfiddle.net/mori57/PQxJC/

Basically, wrap your input and button in a form, and bind the form to submit: which is handled by a method on your ViewModel. See the comments I've made inline, but here it is for people who don't want to go out to jsFiddle:

<span data-bind="text: testProperty"></span><br />
<!-- wrap the input and button in a form and
   data-bind to submit, with a reference
   to a handler on your viewmodel -->
<form data-bind="submit: updateProfile">
<!-- this must be bound to your shadow value -->
<input type="text" data-bind="value: _tmpTestProperty" />
<button type="submit">save</button>
</form>​

and in your javascript

function testViewModel()
{
  var self = this;

  self.testProperty = ko.observable("Initial");
  // Create the "shadow" property
  // and prepopulate it with testProperty's value
  self._tmpTestProperty = ko.observable(self.testProperty());

  // Create our form handler
  self.updateProfile = function(val){
    // set the testProperty value to the 
    // value of the shadow property
    self.testProperty(self._tmpTestProperty());
  };

}

ko.applyBindings(new testViewModel());​

In this way, your value doesn't change when you lose focus on the text input box, but is only updated when you submit the form.

Jason M. Batchelor
  • 2,951
  • 16
  • 25
  • thanks for reply but i have lots of properties, so is this a good practice to double the properties count ( means create a copy of each property ) ? – Tom Rider Oct 19 '12 at 18:57
  • I'd consider, whether using Knockout or jQuery or plain old Javascript, how many things I'd need to keep actively updated, and only update or bind the properties I **must** update dynamically. I don't know what the performance overhead of Knockout is, or what the upper limit of fields bound is (if any), but with all else being equal, go with Occam's Razor: the simplest solution is the best solution. If you find yourself overcomplicating, it might be time to step back and re-evaluate the problem you're trying to solve, and see if there's a simpler solution. – Jason M. Batchelor Oct 19 '12 at 19:06
1

Your simplest approach would be to have a shadow property for each of your properties. So you bind one to your text boxes and only copy the value to the other property, the one bound to the other UI elements, when save is clicked.

See here: http://jsbin.com/aguyud/5/edit

An easier way using two models and $.extend to copy from one to the other:

http://jsbin.com/aguyud/7/edit

Update, actually scratch that, that doesn't seem to work. I tried this instead:

http://jsbin.com/aguyud/22/edit

which works the first time, but after copying the model with $.extend it seem it's copied all the bindings too, so it only works once!

Matt Burland
  • 44,552
  • 18
  • 99
  • 171
  • thanks for reply but i have lots of properties, so is this a good practice to double the properties count ( means create a copy of each property ) ? – Tom Rider Oct 19 '12 at 18:57
  • @TomRider: Another way to approach it would be to create two separate models. You can bind more than one model on a page if they have different parent DOM elements. Then you can have one bound as editable, and another bound as the display. When you click save, you simply copy the editable values to the display one. Or better yet just [clone it](http://stackoverflow.com/questions/122102/what-is-the-most-efficient-way-to-clone-a-javascript-object). A little easier than having two copies of every variable perhaps? – Matt Burland Oct 19 '12 at 19:01
  • @TomRider: I added another version in my answer which removes the complexity of keep copies each property by just keep two models. It works as long as you can bind each model to a different DOM element. Alternatively, you could nest them within a single parent view model to remove that restriction also. – Matt Burland Oct 19 '12 at 19:15