Reversing a content array - ember.js

I'm storing a list of search terms in my ArrayController. I'd like the search terms to be displayed newest to oldest. By default Ember outputs them in order.
You can see my current implementation here: http://andymatthews.net/code/emberTweets/
And here's the pertinent code.
{{#each App.recentUsersArray.reverse}}
<li>
<a href="#" title="view again" {{action "searchAgain" target="App.recentUsersArray"}}>{{this}}</a>
</li>
{{/each}}
App.recentUsersArray = Em.ArrayController.create({
content: [],
reverse: function(){
return this.content.reverse();
}.property(),
});
You can see that I'm trying to reverse it using a property() method but it's not working. Am I doing something wrong?

You should always use get and set to access properties. Also if a computed property depends on other ones, you have to add these in the property declaration. The use of cacheable can be omitted in the next release of ember, see discussion. You can see a working example here.
reverse: function(){
return this.get('content').toArray().reverse();
}.property('content.#each').cacheable()
You could also use the unshiftObject method on an array and hereby circumvent creating a computed property, see http://jsfiddle.net/ez7bV/.

Related

setting #each property, proper use - splitting search results with EmberJs

Im trying to split search results into bulks of 5 so each bulk could be presented desperately.
my data:
Wacky.Video = Ember.Object.extend({
DATA: null
presenter : null
});
The presenter holds the page number on which the data should appear - e.g model[0-5] hold val. 1, model[6-10] hold val. 2 and so on...
my controller:
Wacky.SearchController = Ember.Controller.extend({
...
resPageNum: 1,
...
This property will de/increment whenever a page number will be changed (by button click).
my HTML code:
{{#each res in model}}
{{#if pagePresentor}}
<div class="results">
//DO STUFF WITH RES. OBJECT
</div>
{{/if}}
{{/each}}
finally "pagePresentor" is a property that needs to determine which bulk to present in the current iteration.
So far Iv got this:
pagePresentor: function(value){
return value.presenter == this.get('resPageNum');
}.property('resPageNum','#each.presentor')
But I guess Im using it wrong, because nothing is getting printed at all.
Could anyone please explain how to set this working or at least the base principal for what am I doing wrong here?
Thanks in advance.
pagePresentor: function(value){
return value.presenter == this.get('resPageNum');
}.property('resPageNum','#each.presentor')
Here #each.presentor is a mistake. You should specify observed property which is in the array in the following format: arrayName.#each.propertyName according to http://emberjs.com/guides/object-model/computed-properties-and-aggregate-data/. So, here the name of array which contains the objects with presentor property is missing.

Programmatically setting computed property of an itemController

I have a template with the following code:
{{#each types itemController='type'}}
<div class='col checkbox'>
<label>
{{input type='checkbox' checked=isSelected disabled=notAllowed}}
<span {{bind-attr class='isSelected'}}>{{name}}</span>
</label>
</div>
{{/each}}
types is set in setupController:
this.store.find('type').then(function(types){
controller.set('types', types);
});`
//Having 2 other models here that I am setting and having an itemController for, exactly in the same fashion as types.
for the ArrayController which has the itemController.
NOTE: To clarify, I am using and setting 3 different models, which work pretty much in the same way as type, that makes this a bit more complicated.
Then the itemController itself:
App.TagController = Ember.ObjectController.extend({
isSelected: function(key, value){
//bunch of code that does some stuff and returns true or false depending on value
}.property()
});
App.TypeController = App.TagController.extend();
Now the problem: I have a resetbutton that should deselect all checkboxes and remove the span classes.
I would have thought about using an action (in the ArrayController) that sets all the isSelected properties to false, but I don't seem to be able to find a way to access and manually set that itemController computed property.
One thing I tried in the ArrayController is the following:
actions: {
resetFilters: function(){
this.get('types').forEach(function(type) {
console.log(type.get('isSelected'));
//type.set('isSelected', false);
});
}
}
But unfortunately this returns undefined. And using jQuery manually to remove the class and uncheck the checkbox seems to work the first instance, but the problem is, the computed property doesn't get updated and that messes things up.
Any idea how I can achieve what I want?
If anything is unclear let me know and I will do my best to clarify.
Thank you.
You are setting controller.types, this will not work with itemController. You should always be setting an array controller's content property.
The following should work:
controller.set('content', this.store.find('type'));
Then to set the isSelected:
controller.setEach('isSelected', false);
This assumes that controller is an instance of an ArrayController that has an itemController set in it's definition, e.g.
App.TypesController = Em.ArrayController.extend({itemController: 'type'});
store.find returns a PromiseArray, so it should be resolved first. You can set the types as follows in setupController:
this.store.find('type').then(function(types){
controller.set('types', types);
});
Or you can resolve types in the reset:
this.get('types').then(function(types) {
types.forEach(function(type) {
console.log(type.get('isSelected'));
});
});
I would recommend the first one though.

Ember Navbar needs to show model data upon change

I am working on an application that needs to modify the content of the navbar after login. Here's a basic sketch I put together (with some help from other samples online):
http://jsbin.com/umutag/1/ with this underlying code: http://jsbin.com/umutag/1/edit
How do I get the header view to display model data?
Should I be using a different helper for the template? (e.g. a {{view}}, {{render}}, or {{control}})
BTW, I've scoured this site and others, but most entries are a few months old and I see ember has been changing a lot since then (or I'm missing something obvious). The above example uses Ember 1.0.0 RC6.
Bryan
You ultimately want to bind the value in the controller (probably ApplicationController) that keeps track of whether the user is logged in or not. Since this is pertaining to login, you most likely have something like a SessionController that keeps track of the token. Here's one way to go about it:
App.SessionController = Em.Controller.extend({
token: null,
username: null,
isLoggedIn: function() {
return !!this.get("token");
}.property("token");
// ...
});
App.ApplicationController = Em.Controller.extend({
needs: "session",
isLoggedInBinding: "controllers.session.isLoggedIn",
usernameBinding: "controllers.session.username"
//...
});
And in your navbar in the template:
{{#if isLoggedIn}}
<li>Logged in as {{username}}</li>
<li>{{#linkTo "index"}}Home{{/linkTo}}</li>
<li>{{#linkTo "secret"}}Secret{{/linkTo}}</li>
{{else}}
<li>{{#linkTo "login"}}Log in{{/linkTo}}</li>
{{/if}}

Creating a dynamic string with bindAttr

I'd like to create a dynamic classname on an object with a value I'm getting from my model. One of the keys is named provider which contains either "twitter" or "facebook". What I'd like to do is to prepend the string "icon-" to the provider so that the resulting class is icon-twitter or icon-facebook.
This is the code that I've got now.
<i {{bindAttr class=":avatar-icon account.provider"}}></i>
Ember offers a way to include a static string within the attribute by prepending : to it. You can see that I'm also adding a class called avatar-icon in this example. I've already tried :icon-account.provider which simply resulted in the literal string "icon-account.provider".
RESPONSE
Nice one. I'm working on a solution similar to your answer right now. Question though: this view will be used within the context of an each loop. How would I pass in the current item to be used within the view? I have this right now:
{{#each account in controller}}
{{#view "Social.AccountButtonView"}}
<i {{bindAttr class="account.provider"}}></i>
{{/view}}
{{/each}}
Is it possible to just do this:
{{#view "Social.AccountButtonView" account="account"}}
?
I have previously stated that attributeBindings would be a suitable solution for this, but I was mistaken. When binding the class attribute of a given View, as pointed out, you should use classNames or classNameBindings. Please refer to the sample below:
App.ApplicationView = Em.View.extend({
provider: 'Facebook',
classNameBindings: 'providerClass',
providerClass: function() {
return 'icon-avatar icon-%#'.fmt(this.get('provider').toLowerCase());
}.property('provider')
});
This will render the following HTML:
<div id="ember212" class="ember-view icon-avatar icon-facebook">
<h1>App</h1>
</div>
Here's a fiddle: http://jsfiddle.net/schawaska/HH9Sk/
(Note: The fiddle is linking to a version of Ember.js earlier than RC)

text field filtering a list using ember + ember data

I'm new at using ember, but already familiar with it, basically following some tutorials here and there and reading the api docs. But tutorials don't go too deep into more complex topics.
These are the details: I already implemented a web page that shows a list of items. The following are the relevant code excerpts from different parts of the app.
// the data model, the view and the controller
App.Item = DS.Model.extend({
name: DS.attr('string')
});
App.ItemsController = Ember.ArrayController.extend();
App.ItemsView = Ember.View.extend({ templateName: 'items' })
// in the router's corresponding route
connectOutlets: function(router) {
router.get('applicationController').connectOutlet('items', App.Item.find())
}
// in the handlebars template
<ul class="items">
{{#each content}}
<li>{{name}}</li>
{{/each}}
</ul>
The data for this list is loaded remotely via ember-data (notice the App.Item.find() call in the route's connectOutlet method above) and a handlebar template displays it, and dynamically updates the list as the data changes. Up to here this is basic ember.
Now I want to have a text field at the top of the list, and when the user types in this text field, the list should be updated, by filtering and showing only the items with a name that matches what the user is typing. The actual definition of what a matching name is, is irrelevant to this question. It could be those names that contain the typed string, or that start with it.
I know my next step is to include a textfield view on top of the list in the handlebars template:
<div class="search-bar">
{{view Ember.TextField}}
</div>
<ul class="items">
{{#each content}}
<li>{{name}}</li>
{{/each}}
</ul>
So my questions at this point are the following:
How do I refer to this text field in javascript code so I can attach a listener to it to detect when it changes?
And more importantly, what do I need to do inside this event listener so the list gets filtered?
I would like to know how to achieve it filtering data loaded locally, but also how to do it by loading the filtering data remotely everytime the user types.
I actually need to implement something slightly more complex than this, but knowing how to do this will help.
You can have a computed property on your controller that filters the content based on a text field.
App.ItemsController = Ember.ArrayController.extend({
// ...
searchedContent: function() {
var regexp = new RegExp(this.get('search'));
return this.get('content').filter(function(item) {
return regexp.test(item.get('name'));
});
}.property('search', 'content.#each.name')
});
Then you just bind your text field to controller.search. Example: http://www.emberplay.com#/workspace/2356272909
To filter data remotely you should have ember data load more items every time search changes. This can be done by sending an event to the router every time there is a change.