Refresh template with updated model data


#1

Hey all,

I’d like some help figuring out what seems to be one small missing piece from my learning experiment. I’m using the code that Robin Ward created for his recent blog post (thanks again Robin!). This code pulls back a list of reddit links and displays them in a tabular format. What I want to do is extend that with an input field that will allow a user to enter a subreddit name (e.g.: wtf) and have it refresh the page with the new data.

I’ve added an input field and button that will allow a user to enter a subreddit and I’ve gotten to the point where you can submit the value & the Ajax call is made but I’m not sure how to refresh the template with the new data.

Hoping someone could give me a little help here. I’m thinking it’s something minor that I’m missing.

Demo link: http://reybango.com/demos/ember/learn/ Git: https://github.com/reybango/emberlearn


#2

In https://github.com/reybango/emberlearn/blob/master/js/app.js#L15 you need to set the returned records as the model (or is it content??) property on your IndexController:

this.set('model', App.RedditLink.findAll( value ));

#3

Thanks for the reply. I had tried that before and received the following error message:

Uncaught Error: assertion failed: an Ember.CollectionView’s content must implement Ember.Array. You passed [object Object]

I’m wondering if the async nature of the Ajax call and promise is the cause of this.

I updated the code and demo so you can see the error.


#4

Sure enough that’s the issue. I updated the code to do this instead:

		that = this;

		App.RedditLink.findAll( value ).then( function(response) {
			that.set( 'model',  response );
		} );

That solved it. The 'that = this" line is so I can maintain a reference to the controller which gets lost within the context of the promise (.then()).

By doing this code, it gives the async Ajax call a chance to return the response and then populate it the model accordingly.

Thoughts?


#5

It depends on when you want to clear the current data. If you set model in the loadList method, then your list will be emptied right away, and populated again once the ajax calls finishes. To have it this way, you need to let the findAll method return the links (which will be empty) right away. When the ajax request is finished the array will be filled, and your view will automatically be updated. It works like a promise. Example:

App.RedditLink.reopenClass({
    findAll: function(subreddit) {
        var links = Em.A();
        $.getJSON("http://www.reddit.com/r/" + subreddit + "/.json?jsonp=?").then(function(response) {
            response.data.children.forEach(function (child) {
                links.pushObject(App.RedditLink.create(child.data));
            });
        });
        return links;
    }
});

#6

That looks much cleaner but why use Ember.A() and pushObject() instead of [] & push()?


#7

I don’t believe there are any differences, as long as you don’t mess with Ember.EXTEND_PROTOTYPES as mentioned in http://emberjs.com/api/classes/Ember.NativeArray.html.


#8

In Ember, you use .get, .set and <*>Object (pushObject, popObject, etc.) so that Ember can see the changes and fire observers.

You don’t need to use Ember.A() if prototype extensions are on (which they are by default), but code inside Ember doesn’t assume prototype extensions are on, so you’ll see a lot of Ember.A() inside of framework code.

The alternative to this approach is to deep-diff the array every time any app code runs, which has serious performance implications. At the moment, we have chosen to go with slightly more clunky APIs that Ember can observe directly.

There are plans in the platform (Object.observe, Array.observe, Proxy, etc.) to make it possible to use raw properties directly, and we plan to make use of them just as soon as all of the needed functionality lands in several browsers and is no longer obviously experimental.

For what it’s worth, I have heavily pushed for Object.observe (and array enhancements) on TC39, and I’ve been focusing on making sure that Proxy satisfies the “virtual object” use-case, so I’m very aware of (and working on) future solutions that will improve the Ember API. For now, it’s a tradeoff between an API that looks like POJOs (but requires deep diffing and dirty checking of all live bindings after user code) or a clunkier API that can be observed directly. Until there’s a third alternative (Object.observe or Proxy) we’ve chosen an API that is not a performance footgun.