How do I trigger change on nested models in backbone-associations? - backbone.js

I have an employee model who has address model with 1-1 relationship. I would like to let Employee model know if some change occurs in Address which in turn is being listened by view.
var Employee = Backbone.AssociatedModel.extend({
relations: [
{
type: Backbone.One, //nature of the relationship
key: 'manager', // attribute of Employee
relatedModel: 'Manager' //AssociatedModel for attribute key
}
],
defaults: {
age : 0,
fname : "",
lname : "",
manager : null
}
});
var Manager = Backbone.AssociatedModel.extend({
});
var EmployeeView = Backbone.View.extend({
initialize: function(){
this.model = new Employee();
this.listenTo(this.model, 'nested-change', this.render);
}
});
'nested-change' does not work when some change happens to Manager. Please help.

Try to set Backbone.Associations.EVENTS_NC = true;
They have changed the default behavior in version 0.6.0

Related

How to get display value of field from controller in ExtJS?

I have a component on my view:
{
xtype : 'socekiliscombo',
name : 'socekilisOid',
labelSeparator : '',
anchor : '25%',
allowBlank : false,
itemId : 'socekilis',
params : {},
listeners : {
specialkey : Ext.emptyFn
}
}
What I want to do is to get this component's display value from a controller. First I tried to get the component itself, but unable to do it. I tried this:
var socekilistarihi = this.getTalihliKayitPanel().getComponent('#socekilis');
I get a value of "undefined".
You can use standard controller refferences.
Ext.define('App.controller.Controller', {
extend: 'Ext.app.Controller',
refs: [{
ref: 'socekilis',
selector: '#socekilis'
}],
getComponentValue: function(){
var component = this.getSocekilis();
var value = null;
if(component){
value = component.getValue();
}
return value;
}
});
Hope it helps.
var socekilisCombo = this.getTalihliKayitPanel().down('socekiliscombo[name="socekilisOid"]'),
socekilisComboValue;
if (socekilisCombo)
{
socekilisComboValue = socekilisCombo.getValue();
}
And check this component really on talihliKayitPanel.

Extjs Show Custom row in grid

I am using Ext JS 3.2. I have a grid. Now I want to customize my existing grid. I want to add hardcoded value as row0, But its not working
Below is my code
My store
var store = new Ext.data.Store({
id : 'user',
proxy : proxy,
reader : reader,
writer : writer, // <-- plug a DataWriter into the store
url: 'cat/view.action?catid='+catid_para+'&teaid='+teaid_para+'&flag='+0,
remoteSort: true,
remoteSort: true,
autoSave : false,
// <-- false would delay executing create, update, destroy
// requests until specifically told to do so with some [save]
// buton.
});
var record = new SiteUtility({
id:'0',
fname:'4',
lname:'3444',
attandance: 'G',
});
var parent_grid=Ext.getCmp('org_grid');
parent_grid.getStore().insert(0,record);
// store.save();
//parent_grid.getView().refresh();
store.load({params:{start:0, limit:10}});
Thanks
try this:
store.load({params:{start:0, limit:10}, callback: function(){
var record = new SiteUtility({
id:'0',
fname:'4',
lname:'3444',
attandance: 'G'
});
store.insert(0,record);
}});
Here you can see how to do that. You need to get the recordType first and create new Record:
var recordType = store.recordType;
var nullRecord = new recordType({
id: '1',
name: "4",
lname: "4",
age: "2",
remarks:"Remarks"
}, null);
store.insert(0, nullRecord);
You can take a look at the Ext Docs.

Preselect items in EXT JS 4.2 Grid

I am trying to preselect items in my EXT grid based on the value of one of the items in the data store.
In my data store I fetch 7 items, the last item I grab 'installed' is a BOOLEAN and I would like to use that to preselect items in my grid.
Here is the code I have so far that is not working...
Ext.require([
'Ext.grid.*',
'Ext.data.*',
'Ext.selection.CheckboxModel'
]);
Ext.onReady(function(){
Ext.QuickTips.init();
var sb = $('#sb_id').val();
// Data store
var data = Ext.create('Ext.data.JsonStore', {
autoLoad: true,
fields: [ 'name', 'market', 'expertise', 'id', 'isFull', 'isPrimary', 'installed'],
proxy: {
type: 'ajax',
url: '/opsLibrary/getLibraryJsonEdit',
extraParams: {
sb_id: sb
},
actionMethods: 'POST'
},
sorters: [{
property: 'market',
direction: 'ASC'
}, {
property: 'expertise',
direction: 'ASC'
}]
});
data.on('load',function(records){
Ext.each(records,function(record){
var recs = [];
Ext.each(record, function(item, index){
console.log(item.data);
if (item.data['installed'] == true) {
console.log('Hi!');
recs.push(index);
}
});
//data.getSelectionModel().selectRows(recs);
})
});
// Selection model
var selModel = Ext.create('Ext.selection.CheckboxModel', {
columns: [
{xtype : 'checkcolumn', text : 'Active', dataIndex : 'id'}
],
listeners: {
selectionchange: function(value, meta, record, row, rowIndex, colIndex){
var selectedRecords = grid4.getSelectionModel().getSelection();
var selectedParams = [];
// Clear input and reset vars
$('#selected-libraries').empty();
var record = null;
var isFull = null;
var isPrimary = null;
// Loop through selected records
for(var i = 0, len = selectedRecords.length; i < len; i++){
record = selectedRecords[i];
// Is full library checked?
isFull = record.get('isFull');
// Is this primary library?
isPrimary = record.get('isPrimary');
// Build data object
selectedParams.push({
id: record.getId(),
full: isFull,
primary: isPrimary
});
}
// JSON encode object and set hidden input
$('#selected-libraries').val(JSON.stringify(selectedParams));
}}
});
I was trying to use an on.load method once the store was populated to go back and preselect my items but am not having any luck.
Im a Python guy and don't get around JS too much so sorry for the noobness.
Any help would be appreciated.
Thanks again!
You should be able to do something like:
//create selModel instance above
data.on('load', function(st, recs) {
var installedRecords = Ext.Array.filter(recs, function(rec) {
return rec.get('installed');
});
//selModel instance
selModel.select(installedRecords);
});
Select can take an array of records.
http://docs.sencha.com/extjs/4.2.1/#!/api/Ext.selection.Model-method-select
//data.getSelectionModel().selectRows(recs);
Didn't work because store's don't have a reference to selection models it is the other way around. You can get a selection model from a grid by doing grid.getSelectionModel() or
you can just use the selModel instance you created
var selModel = Ext.create('Ext.selection.CheckboxModel', {

Extenting BackBone.js Website application - Issues with rendering new view

I'm currently attempting to get upto speed with backbone.js, i figured the best way to do this is to get stuck into the online tutorials and documentation. The online tutorials and sample applications are excellent but in order to build by knowledge i'm attempting to build a sample website CRUD application of my own. For the sample, basically what i'm attempting to do is to merge two current online examples/tutorials. In an attempt to gain a better understanding of working with multiple models, collections and views.
Unfortunately i have gotten stuck... I apologies for the long winded explanation but as a novice i'm attempting to explain the issue as best as possible...
I have based my website application sample on the following tutorial:
https://github.com/ccoenraets/backbone-cellar/tree/master/bootstrap
View online example:
http://coenraets.org/backbone-cellar/bootstrap/
I was able to follow this tutorial and have a working version of the site. Now i wish to extent the application to contain more pages which fit into the application (backbone.js) structure. If you view the tutorial you will notice there is an 'about' page which simply loads a static html template into the application. What i would like to do is add a new page which displays a contact manager. The contact manager is deprived from the following tutorial:
http://net.tutsplus.com/tutorials/javascript-ajax/build-a-contacts-manager-using-backbone-js-part-1/
Please note: at this point in time for simplicity i'm only utilising part 1 of the tutorial.
Ok now to explain where i'm having the issue... Firstly i will outline what i have done. On the application i have added a new link in the headerView called Directory. On the main.js page (example of origianl: https://github.com/ccoenraets/backbone-cellar/blob/master/bootstrap/js/main.js) i have added the code as follows:
var AppRouter = Backbone.Router.extend({
routes: {
"" : "list",
"wines/page/:page" : "list",
"wines/add" : "addWine",
"wines/:id" : "wineDetails",
"about" : "about",
"directory" : "directory"
},
initialize: function () {
this.headerView = new HeaderView();
$('.header').html(this.headerView.el);
},
list: function(page) {
var p = page ? parseInt(page, 10) : 1;
var wineList = new WineCollection();
wineList.fetch({success: function(){
$("#content").html(new WineListView({model: wineList, page: p}).el);
}});
this.headerView.selectMenuItem('home-menu');
},
wineDetails: function (id) {
var wine = new Wine({id: id});
wine.fetch({success: function(){
$("#content").html(new WineView({model: wine}).el);
}});
this.headerView.selectMenuItem();
},
addWine: function() {
var wine = new Wine();
$('#content').html(new WineView({model: wine}).el);
this.headerView.selectMenuItem('add-menu');
},
about: function () {
if (!this.aboutView) {
this.aboutView = new AboutView();
}
$('#content').html(this.aboutView.el);
this.headerView.selectMenuItem('about-menu');
},
directory: function () {
if (!this.directoryView) {
this.directorytView = new DirectoryView();
}
$('#content').html(this.directoryView.el);
this.headerView.selectMenuItem('directory-menu');
}
});
utils.loadTemplate(['HeaderView', 'WineView', 'WineListItemView', 'AboutView', 'DirectoryView'], function() {
app = new AppRouter();
Backbone.history.start();
});
Now for the Directory (Contacts Manger) page, for the sake of the explanation, i have left the model view and collection on the single .js file as per the tutorial - i would of course look to separate the file (into model and view) once i get it working. As per the tutorial the code for the contact manager (directory) is as follows:
//demo data
window.contacts = [
{ name: "Contact 1", address: "1, a street, a town, a city, AB12 3CD", tel: "0123456789", email: "anemail#me.com", type: "family" },
{ name: "Contact 2", address: "1, a street, a town, a city, AB12 3CD", tel: "0123456789", email: "anemail#me.com", type: "family" },
{ name: "Contact 3", address: "1, a street, a town, a city, AB12 3CD", tel: "0123456789", email: "anemail#me.com", type: "friend" },
{ name: "Contact 4", address: "1, a street, a town, a city, AB12 3CD", tel: "0123456789", email: "anemail#me.com", type: "colleague" },
{ name: "Contact 5", address: "1, a street, a town, a city, AB12 3CD", tel: "0123456789", email: "anemail#me.com", type: "family" },
{ name: "Contact 6", address: "1, a street, a town, a city, AB12 3CD", tel: "0123456789", email: "anemail#me.com", type: "colleague" },
{ name: "Contact 7", address: "1, a street, a town, a city, AB12 3CD", tel: "0123456789", email: "anemail#me.com", type: "friend" },
{ name: "Contact 8", address: "1, a street, a town, a city, AB12 3CD", tel: "0123456789", email: "anemail#me.com", type: "family" }
];
//define product model
window.Contact = Backbone.Model.extend({
defaults: {
photo: "/img/placeholder.png"
}
});
//define directory collection
window.Directory = Backbone.Collection.extend({
model: Contact
});
//define individual contact view
window.ContactView = Backbone.View.extend({
tagName: "article",
className: "contact-container",
template: $("#contactTemplate").html(),
render: function () {
var tmpl = _.template(this.template);
$(this.el).html(tmpl(this.model.toJSON()));
//alert('this model: ' + this.model.toJSON().name);
return this;
}
});
//define master view
window.DirectoryView = Backbone.View.extend({
el: $("#contacts"),
initialize: function () {
this.collection = new Directory(contacts);
this.render();
},
render: function () {
var that = this;
_.each(this.collection.models, function (item) {
that.renderContact(item);
}, this);
},
renderContact: function (item) {
var contactView = new ContactView({
model: item
});
this.$el.append(contactView.render().el);
}
});
The changes i have made is simply remove the 'var' and replace with 'window.' to fit the existing stucture of the app. For example:
var DirectoryView = Backbone.View.extend({
becomes:
window.DirectoryView = Backbone.View.extend({
Now to the issue i'm having. I'm able to get the code to output (render) the html code to display the template.
I believe the issue is with the
//define individual contact view
window.ContactView = Backbone.View.extend({
tagName: "article",
className: "contact-container",
template: $("#contactTemplate").html(),
render: function () {
var tmpl = _.template(this.template);
$(this.el).html(tmpl(this.model.toJSON()));
alert('this model: ' + this.model.toJSON().name);
return this;
}
});
Now i know that the data is being parsed correctly as the 'alert' is outputting the names correctly. The problem i'm having is the following line of code:
var tmpl = _.template(this.template);
is throwing the following error: "Uncaught TypeError: Cannot call method 'replace' of null".
I'm clueless on how to fix the issue :(
The DirectoryView.html template code is:
<div class="row">
<div class="span12">
<div id="contact"></div>
<script id="contactTemplate" type="text/template">
<img src="<%= photo %>" alt="<%= name %>" />
<h1><%= name %><span><%= type %></span></h1>
<div><%= address %></div>
<dl>
<dt>Tel:</dt><dd><%= tel %></dd>
<dt>Email:</dt><dd><%= email %></dd>
</dl>
</script>
</div>
I hope i have supplied enough information. Please let me know if there is any more info required.
Thanks for having a look :)
Jake
Cannot call method 'replace' of null
This means that inside the _.template method you are trying to call replace for something that is null, presumably a String. The undescore method looks like this (from annotated source)
_.template = function(text, data, settings) {
settings = _.defaults({}, settings, _.templateSettings);
var matcher = new RegExp([
(settings.escape || noMatch).source,
(settings.interpolate || noMatch).source,
(settings.evaluate || noMatch).source
].join('|') + '|$', 'g');
// This is the only place where replace is used
var index = 0;
var source = "__p+='";
// Replace used on variable text
text.replace(matcher, function(match, escape, interpolate, evaluate, offset) {
// replace used on source that can't be null
source += text.slice(index, offset)
.replace(escaper, function(match) { return '\\' + escapes[match]; });
source +=
escape ? "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'" :
interpolate ? "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'" :
evaluate ? "';\n" + evaluate + "\n__p+='" : '';
index = offset + match.length;
});
source += "';\n";
So the variable text has to be null. In your code text is this.template, so it must be null at the time it is initialized.
Are you sure that when you are extending View to create ContactView, that the #contactTemplate element is loaded in the DOM? The problem must be there. Try console logging this.template to see if it is really null. If you want to make sure the DOM is loaded before running any javascript, wrap them in a jQuery ready function.

Extjs4 Combobox with additional options

I wish to create a combobox that loads a store, but also want to add a few predefined data on it. Is it possible?
I think this is what you need:
Ext.define('App.widget.MyCombo', {
extend : 'Ext.form.field.ComboBox',
displayField: '...',
valueField : '...',
name : '...',
alias : 'widget.mycombo',
fieldLabel : 'My Custom combo',
initComponent: function() {
var me = this;
me.store = Ext.create('Ext.data.Store', {
model : '...',
proxy : {
type : '...',
reader: '...'
}
});
/*After data is loaded append some predefined records.*/
me.store.on('load', function() {
/*Indicates that data must be appended to already loaded data.*/
var append = true;
me.store.loadData([{id : -1, value : 'Default'},
{id: -2, value: 'Second Default'}], append);
});
me.callParent();
}
});
If your store is a list, then you can simply append your items to the list after it is generated at the index you specify.
You can also get the store from the combobox, and then use add() at the index your specify.
As Brian Said, you can "insert" it at the index you specify. When you use "add", it basically appends it to the end of the store.
Here is the signature of the insert function:
insert( Number index, Ext.data.Model[] records )

Resources