Remove a sticky parameter - ember.js

I have an application which displays flight information. All list of all flights is available via http://localhost:4200/flights and a list of all flights from Frankfurt via http://localhost:4200/flights?from=FRA
Below the displayed list are two links for the user to toggle between the views. Unfortunately once a user clicked on the http://localhost:4200/flights?from=FRA link he/she has no way of going back to http://localhost:4200/flights via clicking on the corresponding link. The from=FRA parameter is sticky.
How can I link to the http://localhost:4200/flights page and get rid of the from=FRA parameter?
The code I use:
app/templates/flights.hbs
<ul>
{{#each flight in filteredFlights}}
<li>{{flight.code}} {{flight.from}} - {{flight.to}}</li>
{{/each}}
</ul>
<ul>
<li>{{#link-to 'flights'}}All flights{{/link-to}}</li>
<li>{{#link-to 'flights' (query-params from="FRA")}}Flights from Frankfurt{{/link-to}}</li>
</ul>
app/controllers/flights.js
import Ember from 'ember';
export default Ember.Controller.extend({
queryParams: ['from','to'],
from: null,
to: null,
filteredFromFlights: function() {
var from = this.get('from');
var flights = this.get('model');
if (from) {
return flights.filterBy('from', from);
} else {
return flights;
}
}.property('from', 'model'),
filteredFlights: function() {
var to = this.get('to');
var flights = this.get('filteredFromFlights');
if (to) {
return flights.filterBy('to', to);
} else {
return flights;
}
}.property('from', 'to', 'model')
});
app/routes/flights.js
import Ember from 'ember';
export default Ember.Route.extend({
model: function() {
return this.store.find('flight');
}
});

Just pass 'null':
{{#link-to 'flights' (query-params from='null')}}All flights{{/link-to}}

Related

Update UI for a particular model value in Ember

How to iterate over each model value and based on the value update the handlebar UI.
I am using ArrayController. Basically for a particular value in the model I want to change how I display it.
I am not sure what is wrong in the above code. But it does not function as required.
App.SomeStat = Ember.Object.extend({
target: null,
starts: null
}
{{#each stat in controller}}
{{#if isRestricted}} Do something..
{{/if}}
{{/each}}
App.SomestatController = Ember.ArrayController.extend({
isRestricted: function () {
this.forEach(function(target) {
var t= target.get('target');
return t >= MAGIC_NUMBER;
});
}.property('model.#each.target'),
});
You should setup the ArrayController itemController property to an ObjectController which extends the content for each array content.
App.ExtendIndexController = Ember.ObjectController.extend({
isRestricted: Em.computed(function () {
return this.get('name') === 'red';
}).property('name')
});
App.IndexController = Ember.ArrayController.extend({
itemController: 'extendIndex'
});
Then, you could access the added properties in your template when iterating the controller:
{{#each controller}}
<li>{{name}} ({{isRestricted}})</li>
{{/each}}
http://emberjs.jsbin.com/gexos/1/edit
This case is documented in the Ember guide but I think, this specific case should documented as well.
Try this:
App.CensusStat = Ember.Object.extend({
targetPc: null,
starts: null,
isRestricted: function () {
var offTarget = this.get('targetPc');
return (offTarget &&
(Math.abs(offTarget) >=
Ember.I18n.t('ps.label.census.offtarget.restricted.percentage')));
}.property('targetPc')
});

Ember.js clear controller on transitionToRoute call

I have a route that displays a list of parcels, and an Ember.Select that allows the user to select which state's parcels to show.
Model
App.Parcel = DS.Model.extend({
addresses: DS.attr('array')
});
Route
App.ParcelsRoute = Ember.Route.extend({
state: null,
renderTemplate: function () {
this.render({ outlet: 'parcels' });
},
model: function (params) {
state = params.state;
App.ParcelAdapter.state = state;
App.ImageAdapter.state = state;
return Ember.RSVP.hash({
props: this.store.findAll('parcel'),
states: this.store.findAll('state'),
});
},
setupController: function (controller, model) {
controller.set('states', model.states);
controller.set('props', model.props);
controller.set('selectedState', state);
}
});
Controller
App.ParcelsController = Ember.ObjectController.extend({
selectedState: null,
props: null,
states: null,
first: true,
modelReloadNeeded: function () {
if (this.get('selectedState') != undefined && !this.get('first')) {
this.transitionToRoute('/parcels/' + this.get('selectedState'));
}else{
this.set('first', false);
}
}.observes('selectedState')
});
Handlebars
<script type="text/x-handlebars" id="parcels">
{{view Ember.Select content=states optionValuePath="content.id" optionLabelPath="content.id" value=selectedState}}
<input class="search" placeholder="Search"/>
<ul class="list nav">
{{#each props}}
<li>{{#link-to 'parcel' this}}<h3 class="name">{{addresses.0.street_address}}</h3>{{/link-to}}</li>
{{/each}}
</ul>
</script>
When the select transitions to the new route, both the old routes data and new routes are in the model, but if I reload the page, only the current routes data is loaded. Is there a way to clear the DS.RecordArray for props in the controller without a location.reload() call?

Redirect if Invalid id is given

I have the following Routes
App.Router.map(function() {
this.resource('gradebooks', function() {
this.resource('gradebook', { path: ':gradebook_id' });
});
});
App.GradebooksRoute = Em.Route.extend({
model: function() {
return this.store.find('gradebook');
}
});
App.GradebookRoute = Em.Route.extend({
model: function(params) {
var id = params.gradebook_id;
var gradebook = this.store.find('gradebook', id);
var self = this;
gradebook.then(null, function(reason) {
self.transitionTo('gradebooks');
});
return gradebook;
}
})
Templates:
<ul>
{{#each}}
<li {{bind-attr class="isActive:active"}}>
{{#link-to "gradebook" this}}
{{title}}
{{/link-to}}
</li>
{{/each}}
</ul>
{{outlet}}
It's works fine and dandy except when an invalid id is given. (ex. #/gradebooks/invalid_id).
Currently, the redirection works great (I do get the error Error while loading route: TypeError: Cannot read property 'id' of undefined, but it still redirects. However, the resulting list of gradebooks has the invalid gradebook in the list.
If I manually navigate to #/gradebooks/invalid_id_1, #/gradebooks/invalid_id_2, #/gradebooks/invalid_id_3, etc., the invalid gradebook gets added to the list of gradebooks every time.
Any ideas why? Or is there a better solution?
instead of manually handling the find model promise its better to let ember do it, it will trigger an error event if the find
promise is rejected
App.GradebookRoute = Em.Route.extend({
model: function(params) {
var id = params.gradebook_id;
return this.store.find('gradebook', id);
},
actions: {
error: function(reason) {
alert(reason); // "FAIL"
// Can transition to another route here, e.g.
// transitionTo('gradebooks');
// Uncomment the line below to bubble this error event:
// return true;
}
})
more info http://emberjs.com/guides/routing/asynchronous-routing/

Template not updating when controller property changes

Caveat: This is part of my first ember app.
I have an Ember.MutableArray on a controller. The corresponding view has an observer that attempts to rerender the template when the array changes. All the changes on the array (via user interaction) work fine. The template is just never updated. What am I doing wrong?
I'm using Ember 1.2.0 and Ember Data 1.0.0-beta.4+canary.7af6fcb0, though I guess the latter shouldn't matter for this.
Here is the code:
var ApplicationRoute = Ember.Route.extend({
renderTemplate: function() {
this._super();
var topicsController = this.controllerFor('topics');
var topicFilterController = this.controllerFor('topic_filter');
this.render('topics', {outlet: 'topics', controller: topicsController, into: 'application'});
this.render('topic_filter', {outlet: 'topic_filter', controller: topicFilterController, into: 'application'});
},
});
module.exports = ApplicationRoute;
var TopicFilterController = Ember.Controller.extend({
topicFilters: Ember.A([ ]),
areTopicFilters: function() {
console.log('topicFilters.length -> ' + this.topicFilters.length);
return this.topicFilters.length > 0;
}.property('topicFilters'),
getTopicFilters: function() {
console.log('getTopicFilters....');
return this.store.findByIds('topic', this.topicFilters);
}.property('topicFilters'),
actions: {
addTopicFilter: function(t) {
if(this.topicFilters.indexOf(parseInt(t)) == -1) {
this.topicFilters.pushObject(parseInt(t));
}
// this.topicFilters.add(parseInt(t));
console.log('topicFilters -> ' + JSON.stringify(this.topicFilters));
},
removeTopicFilter: function(t) {
this.topicFilters.removeObject(parseInt(t));
console.log('topicFilters -> ' + JSON.stringify(this.topicFilters));
}
}
});
module.exports = TopicFilterController;
var TopicFilterView = Ember.View.extend({
topicFiltersObserver: function() {
console.log('from view.... topicFilters has changed');
this.rerender();
}.observes('this.controller.topicFilters.[]')
});
module.exports = TopicFilterView;
// topic_filter.hbs
{{#if areTopicFilters}}
<strong>Topic filters:</strong>
{{#each getTopicFilters}}
<a {{bind-attr href='#'}} {{action 'removeTopicFilter' id}}>{{topic}}</a>
{{/each}}
{{/if}}
var TopicsController = Ember.ArrayController.extend({
needs: ['topicFilter'],
all_topics: function() {
return this.store.find('topic');
}.property('model', 'App.Topic.#each'),
actions: {
addTopicFilter: function(t) {
App.__container__.lookup('controller:topicFilter').send('addTopicFilter', t);
}
}
});
module.exports = TopicsController;
// topics.hbs
<ul class="list-group list-unstyled">
{{#each all_topics}}
<li class="clear list-group-item">
<span class="badge">{{entryCount}}</span>
<a {{bind-attr href="#"}} {{action 'addTopicFilter' id}}>{{topic}}</a>
</li>
{{/each}}
</ul>
your observes should just be controller.topicFilters.[]
And honestly this is a very inefficient way of doing this, rerendering your entire view because a single item changed on the array. If you show your template I can give you a much better way of handling this.
Here's an example, I've changed quite a few things, and guessed on some others since I don't know exactly how your app is.
http://emberjs.jsbin.com/uFIMekOJ/1/edit

Emberjs serialize doesn't call model on {{linkTo}}

I have a route with the following format #/books/book/:bookId
When i am on the #/books and i click into the {{linkTo}}, then my model is not being
executed and the following error is being returned.
Error while loading route: TypeError {}
Uncaught TypeError: Object 4 has no method 'addArrayObserver'
I know that a model is only being executed when you refresh the page with your browser,
so i used the serialize, which according to the docs it should allow my model to be executed
when i click into the {{linkTo}, but it doesn't. It returns the above error.
utils.get is an Ajax call which returns a json back...
Could you tell me what i am doing wrong?
Thank you.
App.Router.map(function() {
this.resource("books", function() {
this.resource("book", {path: "/book/:bookId"});
});
});
var BookModel = Ember.Object.extend({});
BookModel.reopenClass({
find: function(bookId) {
var assets = Ember.A();
utils.get('book/' + bookId, function(response) {
response.assets.forEach(function(c) {
assets.pushObject(BookModel.create(c));
})
});
return assets;
}
});
var BooksModel = Ember.Object.extend({});
BooksModel.reopenClass({
findAll: function() {
var books = Ember.A();
utils.get('books', function(response) {
response.books.forEach(function(c) {
books.pushObject(BooksModel.create(c));
})
});
return books;
}
});
var BookRoute = Ember.Route.extend({
model: function(params) {
return BookModel.find(params.bookId);
}
,serialize: function(model, params) {
return { bookId: model };
}
});
<h2>books</h2>
<ul class="nav nav-tabs nav-stacked">
{{#each item in model}}
<li>
{{#linkTo "book" item.id}}{{item.name}}{{/linkTo}}
</li>
{{/each}}
</ul>
{{outlet}}
Basically every object (like your BookRoute) needs to be under your App namespace for ember to be found:
App.BookRoute = Ember.Route.extend({
...
});
Also you should pass the model object to the linkTo helper:
{{#linkTo "book" item}}{{item.name}}{{/linkTo}}
and then in your serialize hook you then do:
serialize: function(model) {
return { bookId: model.id };
}
Hope it helps.