Save previous state URL when transition to another route - ember.js

When I transition to a new route, is there any way to store previous state with all the parameters?
Browser back button kinda work so I guess window.history.back() instead of link-to helper would work for me, but I am curious is there any Ember way to save a state and transition to it later?
Thanks

Not sure, if this case works for you but I have saved the previous state and then make the transition to that state in a tab menu which needed to save the state for each specific menu.
App.MenuRoute = Em.Route.extend({
actions: {
willTransition: function(transition) {
var handlers = this.router.router.targetHandlerInfos;
var handler = handlers[handlers.length-1];
this.controller.set('lastHandler', handler);
},
selectMenu: function(value) {
var handler = this.controllerFor(value).get('lastHandler');
var routeName = (handler) ? handler.name : value;
var model;
if ( handler && handler.isDynamic ) {
model = handler.context;
}
if ( model ) {
this.transitionTo(routeName, model);
} else {
this.transitionTo(routeName);
}
}
}
}
});

Related

Ember loading state not triggered on transitionTo

If I use a transitionTo on a route with a slow model hook, the loading.hbs state never gets triggered (I have loading.hbs files at all of the levels -- cluster, cluster.schedule and cluster.schedule.preview_grid). I tried renaming the one at cluster.schedule preview_grid-loading.hbs with no luck.
On the transitionTo, there is no model or model id passed in, just the route:
viewPreviewGrid: function() {
this.transitionTo('cluster.schedule.preview_grid');
},
I also have a loading action defined as follows:
loading(transition) {
var controller = this.controller;
if (!Ember.isNone(controller)) {
this.controller.reset();
}
transition.promise.finally(function() {
NProgress.done();
});
}
During the transitionTo call the page just stays on the previous route until the promises in the model hook resolve, and then it transitions to the other route. If I refresh the page, the loading state gets triggered just fine. Is this a known behaviour for transitionTo?
This is my model hook:
model: function (/*params*/) {
var socialProfile = this.modelFor('cluster.schedule').get('firstObject');
if (!socialProfile.get('isInstagram')){
throw new Error("Attempted to access preview with non-ig profile: " + socialProfile.get('id'));
}
var accessToken = socialProfile.get('token');
var self = this;
return Ember.RSVP.hash({
igPosts: new Ember.RSVP.Promise(function(resolve) {
self.getUsersRecentMedia(accessToken).then(function(response) {
var igPosts = Ember.A([]);
response.data.forEach(function(data) {
igPosts.pushObject(self.igPostFromResponse(data, socialProfile));
});
resolve(igPosts);
});
}),
posts: new Ember.RSVP.Promise(function(resolve) {
self.store.query('gram', { type: 'preview', social_profile_id: socialProfile.get('id'), limit: self.get('postLimit') }).then(function(grams) {
var filteredGrams = grams.filter(function(gram) {
return (gram.get('scheduledInFuture')) && (gram.belongsTo('socialProfile').id() === socialProfile.get('id')) && (gram.get('active'));
});
resolve(filteredGrams);
});
}),
igUser: new Ember.RSVP.Promise(function(resolve) {
self.getSelf(accessToken).then(function(response) {
resolve(self.igUserFromResponse(response.data, socialProfile));
});
})
});
},
You need to return true at the end of the loading() hook to tell Ember to go ahead and show the default loading route (loading.hbs).
loading(transition) {
var controller = this.controller;
if (!Ember.isNone(controller)) {
this.controller.reset();
}
transition.promise.finally(function() {
NProgress.done();
});
return true;
},

how to remove Attachment for specific model in openrp?

I'm developing my own model. I installed Document model. This model is giving attachment button on top of the form. but i want this attachment button in only my module. I want to hide other that button in other form (other model).
so I'm getting following code for removing "create and save" for specific model. but this coding is not working my side. please tell me how to use attachment button for specific model? and how to hide other models?.
openerp.web_smile_hide_buttons = function(openerp) {
// Models for which we'll hide create and duplicate buttons
var MODELS_TO_HIDE = ['kit.lab'];
// Hide the create button on all list views, which affect tree views and many2one pop-up search view
openerp.web.ListView.include({
start: function() {
var self = this;
var ret = this._super.apply(this, arguments);
var res_model = this.dataset.model;
if ($.inArray(res_model, MODELS_TO_HIDE) != -1) {
self.options.addable = false;
};
return ret;
},
});
// Hide the save button on form views
openerp.web.FormView.include({
on_loaded: function(data) {
var self = this;
var ret = this._super.apply(this, arguments);
var res_model = this.dataset.model;
// if ($.inArray(res_model, MODELS_TO_HIDE) != -1) {
this.$element.find('button.oe_dropdown_toggle.oe_dropdown_arrow').remove();
this.$element.find('button.oe_form_button_save').remove();
//};
return ret;
},
});
// Hide the create and duplicate button on all page views (i.e. read-only form views)
openerp.web.PageView.include({
on_loaded: function(data) {
var self = this;
var ret = this._super.apply(this, arguments);
var res_model = this.dataset.model;
if ($.inArray(res_model, MODELS_TO_HIDE) != -1) {
this.$element.find('button.oe_form_button_create').remove();
this.$element.find('button.oe_form_button_duplicate').remove();
};
return ret;
},
});
};
This question is older, but I had the same problem and figured it out. Its most likely not the best solution, but it works. I assume you know how to write a custom module, so just add a dependency to "document" and create an own javascript (e.g. static/src/js/document.js, don't forget to include it in your openerp.py) with the following content:
openerp.document = function (instance) {
_t = instance.web._t;
instance.web.Sidebar.include({
init : function(){
this._super.apply(this, arguments);
if (window.location.href.indexOf('&model=res.partner') === -1)
this.sections.splice(1, 0, { 'name' : 'files', 'label' : _t('Attachment(s)'), });
this.items['files'] = [];
},
});
};
In this example the "Attachment" button will be hidden in the res.partner form view.
Maybe someone else knows a better way to look for the current model compared to my solution to look for the string in window.location.href

How can I programmatically add/remove models to a controller?

This shouldn't be too hard.
I have a datepicker UI widget, and each time the user clicks on a month, I want to add or remove that month from the MonthsController (an ArrayController). The MonthsController is not associated with a route, so in my ApplicationTemplate I simply have
{{render months}}
A simplified version of my datepicker view is
App.DatepickerView = Ember.View.extend({
click: function(e) {
var id = $(this).datepicker().data('date').replace(" ", "-");
this.get('controller.controllers.months').toggleMonth(id);
}
});
and I handle the event in my MonthsController:
App.MonthsController = Ember.ArrayController.extend({
toggleMonth: function(id) {
var month = App.Month.find(id),
index = this.indexOf(month);
if (index === -1) {
this.pushObject(month);
} else {
this.removeAt(index);
}
}
});
I thought I had this working, but then I realized that month in the last snippet wasn't really an App.Month, it was just (I suppose) an anonymous object.
How can I programmatically add/remove models to a controller?
Your App.Month.find(id) will return a promise. If that month hasn't loaded yet you would also be loading this data from the server. You need to wrap your code in the promise's then.
toggleMonth: function(id) {
var _this = this;
App.Month.find(id).then(function(month) {
var index = _this.indexOf(month);
if (index === -1) {
_this.pushObject(month);
} else {
_this.removeAt(index);
}
});
}

Ember - how to create and bind a Checkbox controller?

This question is linked to the answer given here.
Having a checkbox in a view
App.RoleCheckbox = Em.Checkbox.extend({
userRolesBinding: 'parentView.user.roles', // Points to the roles of the user
checked: function () {
var userRoles = this.get('userRoles');
return userRoles.contains(this.get('content'));
}.property('content', 'userRoles.#each'),
click: function (evt) {
//do something
var controller = this.get("controller");
controller.clicked(evt);
}
});
I would like that the click function calls the clicked function from the RoleCheckboxController:
App.RoleCheckboxController = Em.Controller.extend({
clicked: function(evt){
//Really do the thing
}
});
But this does not work. How could I fix this ?
JSFiddle: http://jsfiddle.net/3fMpD/
You can instantiate and associate the controller to the view using the correct naming conventions.
For example, this would associate the controller to the view:
// Instead of App.RoleCheckBoxController
App.ApplicationController = Ember.Controller.extend( /* ... */ );
App.ApplicationView = Ember.View.extend( /* .. */ );
JSFiddle: http://jsfiddle.net/YL5rQ/
#c4p is definitely right and the problem there is that your controller is not being created, and furthermore App.RoleCheckbox has no way of knowing it should use App.RoleCheckboxController as its controller.
I am not quite sure if this is the most Ember-y way of doing this but you can set the controller in the init (constructor function) of the Checkbox view, and then just make sure you send to the controller all the properties it needs to work with:
App.RoleCheckbox = Em.Checkbox.extend({
init: function(){
this._super();
this.set('controller', new App.RoleController());
},
userRolesBinding: 'parentView.user.roles',
checked: function () {
var userRoles = this.get('userRoles');
return userRoles.contains(this.get('content'));
}.property('content', 'userRoles.#each'),
click: function (evt) {
this.get('controller').send('clicked',this.checked, this.content);
}
});
And the controller's code (just changing the parameters used in the function);
App.RoleCheckboxController = Em.ObjectController.extend({
clicked: function(checked,role){
var userRoles = App.User.roles;
console.log("userRoles = ", userRoles);
console.log("role = ", role);
console.log("will be: ", !checked ? "removed" : "added");
if (checked) {
userRoles.pushObject(role);
} else {
userRoles.removeObject(role);
}
console.log("updated userRoles = ", userRoles);
}
});
Working fiddle here: http://jsfiddle.net/cfSwq/3/
Hope this helps!
Your App.RoleCheckboxController is never created. The way you have things set up there will only be an instance of ApplicationController.
You can move the logic back into the view's click event to have everything work:
App.RoleCheckbox = Em.Checkbox.extend({
userRolesBinding: 'parentView.user.roles',
checked: function () {
var userRoles = this.get('userRoles');
return userRoles.contains(this.get('content'));
}.property('content', 'userRoles.#each'),
click: function (evt) {
console.log("event triggered:", evt);
//var controller = this.get("controller");
//controller.clicked(evt);
var isPresent = this.get('checked'),
userRoles = this.get('userRoles'),
role = this.get('content');
console.log("userRoles = ", userRoles);
console.log("role = ", role);
console.log("will be: ", isPresent ? "removed" : "added");
if (!isPresent) {
userRoles.pushObject(role);
} else {
userRoles.removeObject(role);
}
}
});
Updated JSFiddle

Ember.js - currentViewBinding and stop re-rendering on every view transition

I have a statemachine and I am using the new currentViewBinding to swap out parts of an overall containerView whenever a new state is entered using currentViewBinding:
index: Ember.State.create({
enter: function(manager) {
App.get('appController').set('feedView', Ember.View.create({
templateName: 'dashboard_feed',
contentBinding: 'App.feedController.content',
controller: App.get('App.feedController')
}));
}
})
At this moment in time, the rendering of these view is quite slow. Is there a way I could keep the view in memory and avoid the re-rendering every time I enter the state?
I actually provided a solution to this for another question on StackOverflow, but it's super relevant here too. Avoiding re-rendering of a flash object from scratch when view is reactivated
Here's the jsFiddle: http://jsfiddle.net/EE3B8/1
I extend ContainerView with a flag to stop it from destroying the currentView upon it's destruction. You'll want to stash the view instance somewhere that it won't be destroyed.
App.ImmortalContainerView = Ember.ContainerView.extend({
destroyCurrentView: true,
willDestroy: function() {
if (!this.destroyCurrentView) { this._currentViewWillChange(); }
this._super();
}
});
App.immortalView = Ember.View.create({
template: Ember.Handlebars.compile(
'I WILL LIVE FOREVER!'
)
});
​
You could extend Ember.ContainerView to show/hide its currentView view like so:
App.FastContainerView = Ember.ContainerView.extend({
toggleCurrentViewFast: true,
_currentViewWillChange: function() {
var childViews = this.get("childViews"),
currentView = this.get("currentView");
if (this.toggleCurrentViewFast && childViews.indexOf(currentView) >= 0) {
currentView.set("isVisible", false);
} else {
this._super();
}
},
_currentViewDidChange: function() {
var childViews = this.get("childViews"),
currentView = this.get("currentView");
if (this.toggleCurrentViewFast && childViews.indexOf(currentView) >= 0) {
currentView.set("isVisible", true);
} else {
this._super();
}
}
});