I need to know (in JS) when my model (using knockout.js) or rather a propery has changed.
How do I do that?
Here some code:
function DrawingToolViewModel() {
var self = this;
self.drawMode = ko.observable('Line');
}
model = new DrawingToolViewModel();
ko.applyBindings(model);
Now the assigned HTML element to drawMode will be updated by the model and back, whatever changes. That's fine, but how can I react in JS if something in the model has changed?
EDIT
My question wasn't clear enough, sorry. I know observables but I want to subscribe to ALL properties without doing that for every single property. More like "notify me if something in the model has changed"
If you want to register your own subscriptions to be notified of changes to observables, you can call their subscribe function, for example:
myViewModel.personName.subscribe(function(newValue) {
alert("The person's new name is " + newValue);
});
More details # knockoutjs.com
Summarizing the comments below
To get notified on every change in the ViewModel, check Ryan Niemeyer article and John papa's changeTracker on NuGet
If you want to be notified when a specific property changes then there are several ways of doing what you want. One way is to use the subscribe function:
model.drawMode.subscribe(function(newValue) {
// your js goes in here
});
EDIT
However, if you want to be notified when ANY property changes on your view model then I would take a look at this post for creating a 'dirty flag':
http://www.knockmeout.net/2011/05/creating-smart-dirty-flag-in-knockoutjs.html
This effectively tracks any changes to your view model so you should be able to adapt it to your needs.
Related
I recently started learning mithril.js and I'm wondering how can I make very basic Model -> View one way data binding app.
TestModel = function(data){
this.name = m.prop(data.name)
}
testModel = new TestModel({name: "John"})
code above declare a model and it works perfectly as getter/setter.
but how can I set an event listener for the model event like Backbone's listenTo('model',"change",callbackFunc)?
all sample codes I saw are setting events for actual user actions like click,keyup or onchange.but never listen to actual model value's state directly.
am I missing something or am I understanding how to use mithril.js wrongly?
thanks in advance.
One of the key ideas with Mithril is that changes usually happens after an event:
A user action like onclick or keyup defined in a m() view template
An ajax request made with m.request
Mithril automatically redraws after those, alleviating the need for most listeners.
If you are updating your models through some other method and you need to redraw manually, use m.redraw or m.startComputation / m.endComputation. Thanks to Mithril's DOM diff algorithm, redraws are very cheap so don't be afraid to use them (with some common sense, of course!) Check out the m.redraw documentation for more info.
I've a view with knockout.js which has some textboxes and dropdowns.
known when the user changes a value i save the data with a $post
for this i created some computed propties like
self.subjectChanged ko.computed(function () {
var subject self.subject();
//save...
But this also triggers when the subject was loaded from database and set for first time.
What is the best practice for this ?
A similar problem is that i have a function getdata() which depends on two properties.
Now on load this method is raised twice (for each property)
What are best practices to handle this szenarios ?
One way of doing it is to load the page and bind the data as normal, and then use subscriptions to monitor changes to the observable you are interested in.
http://knockoutjs.com/documentation/observables.html#explicitly-subscribing-to-observables
viewModel.subject.subscribe(function(newValue) {
// code you want to run when the value changes...
});
for example http://jsfiddle.net/m8mb5/
This may not be best practice, but in the past I tied a loaded variable to the vm and when the data finished loading from the server I set it to true;
In my computeds I would surround the code that actually did the work in an if that checked the loaded. Computeds can be a little tricky though, you may need to reference the observables outside of the if to ensure they fire correctly.
com = ko.computed(function(){
if(loaded){
var subject = self.subject();
}
// reference observable outside of if to ensure the computed fires when the observable changes
self.subject();
});
All, I am a newbie of Backbone. and I am trying to understand the Model of Backone. Especially how to define a Model. so far, I didn't saw a clear or formal way about how to define a Model for backbone.
For example Let's see the set method in help doc .
set
model.set(attributes, [options])
Set a hash of attributes (one or many) on the model.
Say we have some code like below . I think set method actually is assign a javascript object to the Model.
window.Employee = Backbone.Model.extend({
validate:function(attrs){
for(var key in attrs){
if(attrs[key] == ''){
return key + "can not be null";
}
if(key == 'age' && isNaN(attrs.age)){
return "age is numeric";
}
}
}
});
....
var attr = {}; // I can't not sure what is {} mean.
$('#emp-form input,#emp-form select').each(function(){
var input = $(this);//using jquery select input and select. and enumerate all of them.
attr[input.attr('name')] = input.val();//I am not sure what does it means
});
if(employee.set(attr)){
Employees.create(employee);
}
....
in this example ,I didn't saw the classical way which we can see in java class or c# class to define the class fields or methods. but only see a validate function .Is there anybody who can tell me more about it to help me understand? thanks.
To define a model in Backbone you have to extend the Backbone.Model object. For example if you'll like to create a new User model you could write something like this:
var User = Backbone.Model.extend({})
You can also overwrite some model methods to fill your needs. For example you can change the urlRoot attribute to tell the model where should he fetch the data.
Backbone models contain your data in the attributes attribute. You change those attributes by using the model set method and you can read the value stored in the model using the get method. So if you had some inputs where a user can enter information, for example creating a new user with his name and email and you have a form with a text input for both of them. You could do domething like this:
var user = new User;
user.set('name', $('#name').val());
user.set('email', $('#email').val());
attributes = {
name: user.get('name'),
email: user.get('email')
};
user.save(attributes);
There are a lot of ways to re-factor this code to make it look better but it help to see how you could use those methods. You should check the Backbone documentation to explore how they work a little bit more. Hope this helps!
PD: In my example I set an attribute a time, but you could also send a hash of attributes to set more values in one call.
The model in JS is basically a wrapper for data, with CRUD and simple validation functions. To work properly you need to make server functions to work with (ajax), I think this tutorial says it all http://backbonetutorials.com/what-is-a-model/. Instead of database the model works with your application server side.
If you have custom actions (not just add/edit/remove) on your data, you can manually "set()" data, use "onchange" event and refresh your view when needed. You can even attach "onchange" events only on specific fields and make custom functions in your view to handle each special field (for validation or display).
You can define fields at initialize and defaults value, but not custom functions (ofc you can do model.customFuntion() but I don't recommend it.
In order to make it more "clasical way" you need to use the other Backbone functions http://backbonejs.org/#Collection-Underscore-Methods and Backbone.Collection.
Perhaps this seems a bit backwards, but I have a view bound with Rivets.js for which I'd like the view to populate the model on initialization.
The usecase is that I'm using server-side rendering to return a snippet (the view) including rivets' data-attributes. So NO JSON is returned from server to client.
Now, by pressing 'edit' a user may put the content in 'edit'-mode, and start editing at will. (Using contenteditable, but this is out of scope here I guess).
So how to make sure the model is populated with values from the view on init?
I know that this question is a little outdated but I recentry tried rivets and I came across the same problem.
The solution:
// In your rivets configuration you disable preload:
rivets.configure({
templateDelimiters: ['[[', ']]'],
preloadData: false
});
// you bind your data
var binding = rivets.bind($('#auction'), {auction: auction});
// you manually publish it once to populate your model with form's data
binding.publish();
And that's it. I still don't know how to disable prelaod per bind
From the example on Rivets website (assign to 'rivetBinding')
var view = rivets.bind($('#auction'), {auction: auction});
doing rivetBinding.publish(); will bootstrap the model with values from the view for all bindings that have 'publishes = true'.
This question is old but it still has no accepted answer, so here goes:
You need to disable the preload configuration so rivets doesn't override whatever is in the input with what you have in your model at the time you do the binding. This can be done via the preloadData=false configuration, either globally (rivets.configure(...)) or view-scoped (third param to rivets.bind(...)).
After the binding, you need to publish the view (pull the values to your model). You also need to set up the observers via sync() call, otherwise your binded methods won't be triggered.
Using the same example as the previous answers:
var view = rivets.bind($('#auction'), { auction: auction }, {
preloadData: false
});
view.publish();
view.sync();
The title of the question pretty much sums it up, I'd like my view to respond differently to a model instances initial save vs any future saves. Right now I'm grabbing the model's isNew attr before I save and then triggering a custom event, but I was wondering if there was anything built in?
Checking model.isNew() is the built-in way of telling whether the initial save has happened yet. If checking isNew is working for you, keep on doing it.
The initial save should issue an ID for the object, so you could bind a function to "change:id" and it would execute after the initial save succeeds. Or you could add logic to the "success" and "error" callbacks of create().
With help from this answer, I came up with the following solution:
var originalSync = Backbone.sync;
Backbone.sync = function(method, model, options) {
console.log(method);
originalSync.apply(Backbone, [method, model, options]);
};
I can now check what method is being called.