Setting dynamic page titles in Durandal 2.1.0 - javascript

I use an observable inside the updateDocumentTitle function that gets a new value after completing an ajax request. But I noticed that the updateDocumentTitle function doesn't fire again after the observable changes its value.
userShell.prototype.router.updateDocumentTitle = function(instance, instruction) {
document.title = instance.userArr().name();
};
I tried wrapping the contents of updateDocumentTitle inside a computed observable, but for some reason when I navigate between user pages that are under the same shell (users/100 to users/105), the computed observable gets called as many times as I have navigated between pages without refreshing.
Are there any other successful ways of setting a dynamic document title?

It's a competition between when updateDocumentTitle() fires and when your AJAX request completes successfully.
Where does your AJAX call get made, in which Durandal handler for the viewModel? You have activate, attached, and compositionComplete handlers to choose from.
[EDIT]
You will need to abandon updateDocumentTitle() in this case. Simply create an observable in your viewModel. Update that observable from the activate handler upon successful completion of your AJAX call. Make sure you bind to that observable in your view. We actually do that ourselves for the same reasons you would need to.
For robustness, make sure you provide a default title in the event your AJAX call fails.

Related

Backbone.sync clarification

After reading the docs, this is my understanding of sync.
I instantiate some Backbone.Model and call Collection.create(). create() eventually calls sync() and the Model is POSTed to the server. Then there is a sync in the opposite direction such that the Model on the client is given an id.
Does this update then trigger componentDidUpdate()?
Note: componentDidUpdate is a ReactJS thing, so if that doesn't make sense, the question reduces to "Is the client-side model updated and the view re-rendered?"
Since inside of my componentDidUpdate() I am making a call to save() to keep everything up to date, this subsequently makes a call to sync() which then fires a PUT request (because the Model already has an id).
I'm asking, because in my current application, creating a TodoItem seems to result in a POST and then a PUT which I find redundant. Perhaps it is for an unrelated reason.
It actually fires two POSTS and then two PUTS when adding one item, but that is another question.
The first time you save a model (one which doesn't have an id) it will make a POST, thereafter it will make a PUT (update). I think you are confusing when to use create/add/save:
Use save at any point to save the current client collection/model state to the server
Use add to add Model(s) to a collection (a single Model, an array of Models, or an array of objects which contain attributes and let the collection create them)
Use create as a shorthand for creating a model, adding it to the collection, and syncing the collection to the server.
My guess is that you are calling create and save in one operation - you should be using add and save instead, or just create.
The view will not automatically update for you, you will need to listen to changes or events on the collection/model and update the view yourself - there is no equivalent of componentDidUpdate. For example:
initialize: function() {
this.listenTo(this.collection, 'sync', this.onCollectionSync);
},
onCollectionSync: function() {
this.render();
}

How to trigger a Client JS method when a subscribed data is changed

I want my app to fire a method (client side) when a particular subscribed data is changed? for example, the client side has this following subscription
Meteor.subscribe('thePlayers');
thePlayers subscription returns a collection of data which is being displayed in the html through the template.
so whenever the collection get changed, Meteor automatically change the data in the HTML also. Besides this feature, I want my app to fire a method say fire() to be executed as soon as data get changed. What should i do to achieve this?
As David Weldon correctly, cursor.observerChanges is the way to go. Here's how you can use it for your example (assuming your collection is called thePlayers):
client-side
methodCaller = function (methodName) {
return function (/* arguments */) {
Meteor.apply(methodName, arguments)
}
}
var fireCaller = methodCaller('fire')
thePlayers.find().observeChanges({
added: fireCaller,
changed: fireCaller,
removed: fireCaller
})
In case you need this fire() to be run on server, you don't need a method, you can just rely on the observeChanges feature or just observe in your publication. See this question to get an example of how you can achieve that.
In case you need this fire() to be run on client, keep in mind that every helper in your template is reactive, that means it will re-run each time your collection is changed. I assume that it requires that you use the subscription inside it, but that needs to be confirmed.

knockout.js preventing first value change

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();
});

Wiring an AJAX call in Knockout.js

Apologies if this has been asked before, I have searched but I'm finding it very hard to express my problem in a search friendly way. And I can't figure it out from the knockout documentation, however it seems like a basic question.
I have 3 select lists and a Knockout view model. Selecting a value in the first list updates an observable in the view model. I then need to make an ajax post, sending that value to the server and retrieving a list of values which I put in an observable array in the view model, which will in turn update the other 2 lists.
I'm happy with wiring up to observables and that part is working fine, my question is how and where to trigger the ajax call.
If I trigger it on the change event of the first select it seems to cause a race condition which means it sometimes gets called before the view model has updated. I could trigger it without using the observable, but that doesn't seem very knockoutish.
If I use a custom binding for retrieving values it will cause the ajax call to be made twice and I can't put the retrieval in a function because it needs to run asynchronously (and it would be called twice).
I feel like I need something which listens to an observable and triggers an ajax call without any visual element.
Any help would be gratefully received.
Triggering things that should happen in response to view model changes generally works through subscriptions in knockout.
function ViewModel() {
var self = this;
self.someValue = ko.observable();
self.otherValue = ko.observable();
self.someValue.subscribe(function (newValue) {
// do something with newValue, like an Ajax request.
// assuming jQuery
$.get("your/url", {val: newValue})
.done(function (data) {
self.otherValue(data);
})
.fail(function () {
alert("could not retrieve value from server");
});
});
}

Ember.js - How to trigger view method from controller?

I'm trying to call view method from controller, but no idea how to do this. From view I can easily call controller method like this.get('controller').send('method');
How to do something like that from controller this.get('view').send('method');?
To give you better overview what I'm trying to do.
I have application controller Ember.Controller.extend({}) I have application view Ember.View.extend({}) and application template.
In application template is login form, when user submit it controller method is executed. In this method if login credentials are incorrect I need to call view method which is executing jQueryUI method on login form (shake method to be exact and showing some text).
This sounds like a good use for Ember.Evented. By using event subscription and dispatching you can avoid coupling your view and controller.
Simply mixin Ember.Evented:
Controller = Ember.Controller.extend(Ember.Evented)
Now you can call on and trigger methods on your controller, to subscribe to an event and then to kick off the event. So, in your view you might do:
didInsertElement: function () {
this.get('controller').on('loginDidFail', this, this.loginFail);
}
And then in your controller call this.trigger('loginDidFail') to kick off your loginFail view method.
Remember to remove the handler after the view is dismissed... see the answer below.
Just wanted to answer on this question to address the issue with properly removing the listener if the view is cleared (when the route changes). It's also not necessary to use a jquery proxy, since the on/off methods support a target, which is good because unsubscribing a proxy is definitely more complicated. Revising what Christopher provided:
didInsertElement: function()
{
this.get('controller').on('loginDidFail', this, this.loginFail);
},
willClearRender: function()
{
this.get('controller').off('loginDidFail', this, this.loginFail);
}
Without removing the subscription any subsequent visits to the login route (without reloading the page) will add additional listeners; i.e. memory leaks, errors, and unexpected behavior.

Categories

Resources