How can I programmatically add/remove models to a controller? - ember.js

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

Related

SelectAll feature with Ember ObjectController and ItemController

I am trying to implement a multiselect row in a table. The parent controller is just an object controller. It has a model, and the view iterates over the recordset of the model as individual rows.
I have implemented an itemController for all the rows in the model. That works.
But for the 'selectAll' functionality, in the parent controller, I am not able to get hold of all the items (individually). Do you have any idea how to go abt it?
Here's my work so far :
export
default Ember.ObjectController.extend({
// parent Controller
itemController: 'checkbox',
selectAll: function(key, value) {
var items = this.get('model.items');
if (arguments.length == 2) {
this.setEach('isSelected', value); //setEach is throwing an error sine it comes from ArrayController where as I am using ObjectController as the parent controller type
return value;
} else {
return this.isEvery('isSelected', true); //isEvery is also throwing error for the same reason
}.property('model.items.#each.isSelected')
And my Item Controller (checkboxcontroller) is as follows :
export default Ember.ObjectController.extend({
isSelected: false,
selectedListOfItems: [],
isSelectedChange: function() {
var selectedListOfItems = this.get('selectedListOfItems');
var itemId = this.get('id'); // comes from the model.items.id
debugger;
if (this.get('isSelected')) {
// add itemId to the selected array
var index = selectedListOfItems.indexOf(itemId);
if (index > -1) {
selectedListOfItems.splice(index, 1, itemId);
} else {
selectedListOfItems.push(itemId);
}
} else {
// remove itemId from the selected array
var index = selectedListOfItems.indexOf(itemId);
if (index > -1) {
selectedListOfItems.splice(index, 1);
}
}
this.set('selectedListOfItems', selectedListOfItems);
}.observes('isSelected')
});
My doubt is how do I do selectAll on the parent controller (that is of ObjectController type) that selects all the checkboxes of all the children. I am not sure if the info I've provided above is enough. Kindly let me know if you need more info. Thanks in advance
I got it working by adding a listener to the child (ItemController) that listens for any change in the parent's variable.
Here's what I did :
parentControllerDidChange: function() {
if (this.get('parentController.selectedAllItems')) {
this.set('isSelected', true);
} else {
this.set('isSelected', false);
}
}.observes('parentController.selectedAllItems')
That did the trick. Now If I toggle the boolean variable on the parent controller, all the children react. Ember the beauty !

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

Save previous state URL when transition to another route

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

Emberjs how can I make collection arrangedContent and searchResults work together?

I have a controller that observes a search field like so:
Scrolls.IndexController = Ember.ArrayController.extend({
searchResult: function() {
var that = this;
this.get('model').set('content', this.store.filter('scroll', function(item) {
var searchTerm = that.get('searchCard');
var regExp = new RegExp(searchTerm, 'i');
return regExp.test(item.get('name'));
}));
}.observes('searchCard')
});
Which works great, but once I add a method that overrides arrangedContent to limit the returned items, it stops re-rendering.
Scrolls.IndexController = Ember.ArrayController.extend({
arrangedContent: Ember.computed('content', function() {
var count = 0;
return this.get('content').filter(function() {
count++;
return count <= 3;
});
}),
searchResult: function() {
var that = this;
this.get('model').set('content', this.store.filter('scroll', function(item) {
var searchTerm = that.get('searchCard');
var regExp = new RegExp(searchTerm, 'i');
return regExp.test(item.get('name'));
}));
}.observes('searchCard')
});
How can I get make what I'm doing to behave nicely with each other?
I see a few things here that jump out to me. First one being, in the context of a controller, content and model are the same thing so in the observer, when you do:
this.get('model').set('content'
You're setting a property of 'content' on the model when I think you actually intend to set the content directly on the controller, like this:
this.set('content',
I also kind of wonder whether you really need to override the content and arrangedContent properties (not sure what the calling code looks like). I suspect that might cause some bugs later. Instead, I wonder if you could set it up like this:
Scrolls.IndexController = Ember.ArrayController.extend({
firstThreeSearchResults: function() {
var count = 0;
return this.get('searchResults').filter(function() {
count++;
return count <= 3;
});
}.property('searchResults'),
searchResults: function() {
var searchTerm = this.get('searchCard');
return this.store.filter('scroll', function(item) {
var regExp = new RegExp(searchTerm, 'i');
return regExp.test(item.get('name'));
});
}.property('searchCard')
});
Final possible problem is the use of the filter function called on the store. According to the docs, this function: "returns a live RecordArray that remains up to date as new records are loaded into the store or created locally." The problem being, though the filter might update as new results are added, it might not cause the computed property that looks for the first three results to update. That is, the binding on that computed property might not fire. One way to get around this would be to do something like this:
Scrolls.IndexRoute = Ember.Route.extend({
model: function() {
return this.store.find();
}
});
Scrolls.IndexController = Ember.ArrayController.extend({
firstThreeSearchResults: function() {
var count = 0;
return this.get('searchResults').filter(function() {
count++;
return count <= 3;
});
}.property('searchResults'),
searchResults: function() {
var searchTerm = this.get('searchCard');
return this.get('content').filter(function(item) {
var regExp = new RegExp(searchTerm, 'i');
return regExp.test(item.get('name'));
});
}.property('searchCard', 'content.length')
});

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