Implementation of displaying breadcrumb path in ember with sample code or may be direct me to some repository - ember.js

Can some one redirect me to some project code or some working example of displaying crumble path in ember?
This code doesn't work for some reason.
ApplicationController = Ember.Controller.extend({
needs: ['breadcrumbs'],
hashChangeOccured: function(context) {
var loc = context.split('/');
var path = [];
var prev;
loc.forEach(function(it) {
if (typeof prev === 'undefined') prev = it;
else prev += ('/'+it)
path.push(Em.Object.create({ href: prev, name: it }));
});
this.get('controllers.breadcrumbs').set('content',path)
}
});
ready : function() {
$(window).on('hashchange',function() {
Ember.Instrumentation.instrument("hash.changeOccured", location.hash);
});
$(window).trigger('hashchange');
}
App.ApplicationRoute = Ember.Route.extend({
setupController: function(controller, model) {
Ember.Instrumentation.subscribe("hash.changeOccured", {
before: function(name, timestamp, payload) {
controller.send('hashChangeOccured', payload);
},
after: function() {}
});
}
});

Here you have a starting point:
APP.Breadcrumb = Em.View.extend({
classNames: ['breadcrumb'],
tagName: 'ul',
activeChanged: function () {
var self = this;
Em.run.next(this, function () {
self.set('active', self.get('childViews.firstObject.active'));
});
}.observes('childViews.firstObject.active'),
disabled: function () {
var role = this.get('role');
if (!Em.isEmpty(role)) {
return !this.get('controller.controllers.login').hasRole(role);
}
return false;
}.property("controller.controllers.login.authenticationMediator.roles.#each"),
currentPathChanged: function() {
this.rerender();
}.observes('controller.currentPath'),
template: function () {
var template = [],
controller = this.get('controller'),
router = controller.container.lookup('router:main'),
currentHandlerInfos = router.get('router.currentHandlerInfos');
for (var i = 0; i < currentHandlerInfos.length; i++) {
var name = Em.get(currentHandlerInfos[i], 'name');
if (!(router.hasRoute(name) || router.hasRoute(name + '.index')) || name.endsWith('.index')) {
continue;
}
var notLast = i < currentHandlerInfos.length - 1 && !Em.get(currentHandlerInfos[i + 1], 'name').endsWith('.index');
template.push('<li' + (notLast ? '>' : ' class="active">'));
if (notLast) {
template.push('{{#linkTo "' + name + '"}}');
}
template.push(name);
if (notLast) {
template.push('{{/linkTo}}');
}
if (notLast) {
template.push('<span class="divider">/</span>');
}
template.push('</li>');
}
return Em.Handlebars.compile(template.join("\n"));
}.property('controller.currentPath')
});

Related

Masking Phone in Ember JS

I am trying to mask a Phone number in a input field, can somebody please help me in this regards. Here is my code for the html (or .hbs file)
<label class="control-label">Phone</label>
{{masked-input mask='(999) 999-9999'
value=model.Address.Phone
input-format='regex'
input-filter='\(*[0-9]{3}\) [0-9]{3}-[0-9]{4}'
input-filter-message='Phone number is not valid.'
class='form-control phone masked'
maxlength="14"}}
</div>
And my component definition is as below:
export default () => {
IMS.registerComponent("masked-input", {
tagName: 'input',
attrParams: ['required', 'title', 'name', 'placeholder'],
loaded: false,
prop: Ember.observer(
'required',
'title',
'name',
'placeholder',
'value',
function () {
var scope = this;
$(this.element).val(Ember.get(scope, 'value'));
var stamp = new Date();
if (Ember.get(scope, 'loaded') == true) {
var element = $(this.element);
var attrs = Ember.get(this, 'attrParams');
attrs.forEach(function (attr) {
var value = Ember.get(scope, attr);
if (value == '' | value == null) {
element.removeAttr(attr);
} else {
element.attr(attr, value);
}
})
}
}),
observeMask: Ember.observer('mask', function () {
var scope = this;
$(this.element).inputmask({
mask: Ember.get(scope, 'mask')
});
}),
didInsertElement: function () {
var scope = this;
setTimeout(function () {
var value = Ember.get(scope, 'value');
var element = $(scope.element);
var change = function () { Ember.set(scope, 'value', element.val()); }
element.val(Ember.get(scope, 'value'));
element.attr('type', 'text');
element.change(change);
Ember.set(scope, 'loaded', true);
scope.observeChanges();
element.inputmask({
mask: Ember.get(scope, 'mask')
});
element.attr('input-format', Ember.get(scope, 'input-format'));
element.attr('input-filter', Ember.get(scope, 'input-filter'));
element.attr('input-filter-message', Ember.get(scope, 'input-filter-message'));
}, 250);
}
})
}

I am attempting to upgrade from ember 1.7 to 1.13

I am trying to upgrade from an ancient version of ember 1.7 to the still ancient 1.13 and I am getting .js errors. I am not well versed with ember, to begin with, so all the help I can get will be appreciated.
I changed all instances of the code where it was using Ember.View.extend to Ember.Controller.extend
and since then, I am getting an error
Cannot read property 'noSignedUpAppts' of undefined.
Appt.Ember.js
function initEmberApp() {
Ember.Handlebars.registerBoundHelper('stringFormat', function (g11nString, str) {
return new Handlebars.SafeString(stringUtil.format(g11nString, str));
});
ApptApp = Ember.Application.create({
rootElement: "#appointmentWrapper"
});
ApptApp.Router.map(function () {
this.route("main", { path: '/' });
this.route("mainParam", { path: "/:val" });
this.route('mainId', { path: '/mainId/:appt_id' });
this.route('mainDirect', { path: '/mainDirect/:appt_id' });
this.route("schedule");
this.resource('userSchedule', { path: '/schedule/:user_id' });
this.route('scheduleId', { path: '/scheduleId/:appt_id' });
this.route('userScheduleId', { path: '/userScheduleId/:ids' });
this.route('scheduleSpecific');
this.route('scheduleSpecificId',{path: '/scheduleSpecificId/:appt_id'});
this.route('scheduleDate', { path: '/scheduleDate/:date' });
this.route('scheduleResource', { path: '/scheduleResource/:resource_id' });
this.route("settings");
this.route("campus");
this.route("noAccess");
});
ApptApp.history = {name:'',view:'',param:null, isSchedule:false}
initViews();
}
function initViews() {
initMain(ApptApp);
initSchedule(ApptApp);
initSettings(ApptApp);
initCampus(ApptApp);
initNoAccess(ApptApp);
}
ApptMain.js
function initMain(ApptApp) {
ApptApp.MainController = Ember.Controller.extend({
g11n: apptPortlet.g11n,
ableToEdit: apptPortlet.ableToEdit,
canManageSettings: apptPortlet.canManageSettings,
canAdmin: apptPortlet.canAdmin,
defaultDate: '',
showMySchedule: false,
apptId: '',
isDirect: false
});
ApptApp.MainParamRoute = Ember.Route.extend({
model: function (param) {
var date = moment(param.val.replace(/-/g, '/'));
return { defaultDate: (date.isValid() ? date.format('MM/DD/YYYY') : ''), showMySchedule: (param.val == 'myS') };
},
setupController: function (controller, model) {
this.controllerFor('main').set('defaultDate', model.defaultDate).set('showMySchedule', model.showMySchedule).set('apptId', '').set('isDirect',false);
},
renderTemplate: function () {
this.render('main');
}
});
ApptApp.MainIdRoute = Ember.Route.extend({
model: function (param) {
var items = param.appt_id.split('|');
var date = moment(items[1].replace(/-/g, '/'));
return { apptId: items[0], defaultDate: (date.isValid() ? date.format('MM/DD/YYYY') : '') };
},
setupController: function (controller, model) {
this.controllerFor('main').set('defaultDate', model.defaultDate).set('showMySchedule', false).set('apptId', model.apptId.toLowerCase()).set('isDirect', false);
},
renderTemplate: function () {
this.render('main');
}
});
ApptApp.MainDirectRoute = Ember.Route.extend({
model: function (param) {
var items = param.appt_id.split('|');
var date = moment(items[1].replace(/-/g, '/'));
return { apptId: items[0], defaultDate: (date.isValid() ? date.format('MM/DD/YYYY') : '') };
},
setupController: function (controller, model) {
this.controllerFor('main').set('defaultDate', model.defaultDate).set('showMySchedule', apptPortlet.apptSetting != 0).set('apptId', model.apptId.toLowerCase()).set('isDirect', true);
},
renderTemplate: function () {
this.render('main');
}
});
ApptApp.MainView = Ember.Component.extend({
didInsertElement: function() {
var controller = this.get('controller');
if (this.processRedirect(controller))
return;
this.renderView(controller);
},
renderView: function (controller, isRerender) {
if (isRerender) {
apptFullCal.destroy();
}
var g11n = controller.g11n;
apptFullCal.init({
data: {},
defaultDate: controller.defaultDate,
showMonth: true,
showWeekNav: true,
allowEditing: false,
calElem: $("#myCalendar"),
showWknd: apptPortlet.showWeekends,
updateWknd: apptPortlet.updateSettings,
g11n: controller.g11n,
listViewPageSize: apptPortlet.listViewPageSize,
noApptMesg: controller.g11n.noSignedUpAppts,
rerender: function () {
apptFullCal.reload();
$("#myNotifications").apptNotification('render');
},
editEvent: function(appt, isClick, revertFunc, rerenderAction) {
var resource = {};
if (appt.resourceId != '' && appt.resourceEdit)
resource = apptPortlet.getResource(appt.resourceId);
$.apptDetails({ controller: controller, appointment: appt, g11n: controller.g11n, resource: resource, canAddAttendees: apptPortlet.canAddAttendees, rerender: function () { rerenderAction(); $("#myNotifications").apptNotification('render'); } });
},
readonlySources: function (viewName) { return viewName == 'month' ? [{ url: 'rpc/appointmentsinfo/getcalendaraggregate' }] : [{ url: 'api/calendarevents?fullCalendar=true&filter=conflictable' }]; },
postApptRender: function (appt, elem, view) {
if (appt.isReadOnly) return;
var item = elem.find('.fc-content');
item.html(appt.isOwner ? appt.attendeeInfo : (appt.resourceId != '' ? appt.resourceName : appt.owner));
if (view.name != 'month') {
item.append($("<span class='fc-cus-event-info'>").html(appt.title));
}
if (appt.id == controller.apptId) {
controller.apptId = '';
apptFullCal.triggerClick(appt);
}
if (appt.newCommentCount > 0) {
var ctr = view.name == 'list' ? elem : item;
var comTxt = $("<span class='fc-comment'>").append($("<i class='fa fa-comment'/>")).append(view.name == 'list' ? stringUtil.format((appt.newCommentCount == 1 ? controller.g11n.newComment : controller.g11n.newComments), appt.newCommentCount) : '');
ctr.prepend(comTxt);
}
},
changeView: function(viewName) {
if (viewName == 'list')
$(".apptKeyInfo.otherEvents").hide();
else
$(".apptKeyInfo.otherEvents").show();
if (viewName == 'month')
$(".apptKeyInfo.otherEvents").removeClass("inactiveItem");
else
$(".apptKeyInfo.otherEvents").addClass("inactiveItem");
bindHelpText(g11n, viewName == 'list' ? '2' : (viewName == 'month' ? 0 : 1));
}
}, 'month');
bindHelpText(g11n, 0);
$("#myNotifications").apptNotification({
g11n: apptPortlet.g11n,
baseUrl: apptPortlet.baseUrl,
renderFullTxt: true,
callback: function(apptInfo) {
var date = moment(apptInfo.start);
if ((date.weekday() == 0 || date.weekday() == 6) && apptPortlet.showWeekends == false)
apptFullCal.showWeekends($("#myCalendar"), true, date);
controller.set('apptId', apptInfo.id);
apptFullCal.gotToDate('agendaDay', date);
}
});
$("#peopleChooser").peopleChooser({
peopleSource: 'rpc/appointmentsInfo/GetUserSearch',
watermark: controller.g11n.watermark,
onSelect: function(person) {
if (person.isResource)
controller.transitionTo('scheduleResource', person.id);
else
controller.transitionTo('userSchedule', { id: person.id, imgUrl: person.imgUrl, name: { full: person.fullName } });
}
});
if (controller.canManageSettings || controller.canAdmin)
$(".permissionAction").click(function() { ApptApp.history = { name: '', view: 'main', isSchedule: false }; });
var schLinkAction = this.bindScheduleLink;
$(".permHosts").hide();
if (apptPortlet.canManageSettings && (apptPortlet.apptSetting == 2 || (apptPortlet.apptSetting == 3 && apptPortlet.resourceId.length > 0))) {
var resource = apptPortlet.apptSetting == 2 ? null : apptPortlet.getResource(apptPortlet.resourceId);
if (apptPortlet.apptSetting == 2 || (resource != null && resource.canEdit)) {
$(".permHosts").show().find('a').html("<i class='fa fa-group'></i>" + (apptPortlet.apptSetting == 2 ? g11n.apptHosts : g11n.managersAndHosts))
.unbind('click').click(function(e) {
e.preventDefault();
$.apptManageHosts({
g11n: controller.g11n,
resource: resource,
isResource: resource != null,
portletId: apptPortlet.portletId,
onSave: function(res) {
if (apptPortlet.apptSetting == 2) {
apptPortlet.hosts = res;
schLinkAction(controller);
} else {
apptPortlet.hosts = res.hosts;
}
}});
});
}
}
if (controller.showMySchedule) {
$(".mySchedule").hide();
this.bindResourceInfo(controller);
} else {
$(".mySchedule").show();
}
this.bindSidebar(controller);
},
bindSidebar: function(controller) {
var campus = $(".campusWrapper").hide();
var myfac = $(".myFacWrapper").hide();
$.get('rpc/appointmentsinfo/getsidebarinfo/', function (sidebarInfo) {
if (sidebarInfo == null) return;
if (sidebarInfo.campusResources != null) {
var ul = campus.find('#campusResources').empty();
for (var key in sidebarInfo.campusResources) {
ul.append($("<li>").append($("<a href='#' class='activeItem apptStrong'>").data('id', key).html(sidebarInfo.campusResources[key]).click(function (e) { e.preventDefault(); controller.transitionTo('scheduleResource', $(this).data('id')); })));
}
if (ul.find('li').length > 0)
campus.show();
}
if (sidebarInfo.currentFaculty != null && sidebarInfo.currentFaculty.length > 0) {
myfac.show();
var container = myfac.find(".myFacUsers").empty();
$.each(sidebarInfo.currentFaculty, function (i, fac) {
var div = $("<div class='myFac'>");
div.append($("<a class='activeItem apptStrong'>").html(fac.name).click(function (e) { e.preventDefault(); controller.transitionTo('userSchedule', { id: fac.id, imgUrl: fac.imgUrl, name: { full: fac.name } }); }));
if (!fac.hasAvailAppts)
div.append($("<span class='pc-details'>").html(controller.g11n.noAppt));
$.each(fac.sections, function (j, sec) {
div.append($("<div class='inactiveItem itemInfo'>").html(sec));
});
container.append(div);
});
}
});
},
processRedirect: function (controller) {
if (apptPortlet.name == null) {
controller.transitionTo("noAccess");
return true;
}
if (controller.isDirect) return false;
var date = controller.defaultDate != null && controller.defaultDate != '' ? moment(controller.defaultDate).format('MM-DD-YYYY') : null;
if ((apptPortlet.resourceId != '' || apptPortlet.apptSetting == 2) && !controller.showMySchedule) {
var url = apptPortlet.apptSetting == 2 ? 'scheduleSpecific' : 'schedule';
if (controller.apptId != '' || date != null) {
controller.transitionTo(url + "Id", (controller.apptId + '|' + date));
}
else
controller.transitionTo(url);
return true;
}
else if (apptPortlet.apptSetting == 1 && !controller.showMySchedule && apptPortlet.hosts != null && apptPortlet.hosts.length > 0) {
var host = apptPortlet.hosts[0];
if (controller.apptId != '' || date != null) {
controller.transitionTo('userScheduleId', host.id + '_' + ((controller.apptId == '' ? ' ' : controller.apptId) + '|' + date));
}
else
controller.transitionTo('userSchedule', { id: host.id, imgUrl: host.imgUrl, name: { full: host.name } });
return true;
}
return false;
},
bindScheduleLink: function (controller) {
var showLink = false;
if (apptPortlet.resourceId != '') {
var resource = apptPortlet.getResource(apptPortlet.resourceId);
$(".scheduleLink").html(stringUtil.format(controller.g11n.bckToSchedule, resource.name)).unbind('click').click(function (e) { e.preventDefault(); controller.transitionTo('schedule'); });
showLink = true;
}
else if (apptPortlet.apptSetting == 1) {
var host = apptPortlet.hosts[0];
$(".scheduleLink").html(stringUtil.format(controller.g11n.bckToSchedule, host.name)).unbind('click').click(function (e) { e.preventDefault(); controller.transitionTo('userSchedule', { id: host.id, imgUrl: host.imgUrl, name: { full: host.name } }); });
showLink = true;
}
else if (apptPortlet.apptSetting == 2) {
var names = '';
var userCount = apptPortlet.hosts.length;
for (var i = 0; i < userCount; i++) {
names += " " + apptPortlet.hosts[i].name;
if (userCount > 1 && (userCount - i != 1)) {
names += userCount - i == 2 ? ", " + controller.g11n.and : ",";
}
}
$(".scheduleLink").html(stringUtil.format(controller.g11n.bckToSchedule, names)).unbind('click').click(function (e) { e.preventDefault(); controller.transitionTo('scheduleSpecific'); });
showLink = true;
}
if(showLink)
$(".bckToSchedule").show();
else
$(".bckToSchedule").hide();
},
bindResourceInfo: function (controller) {
this.bindScheduleLink(controller);
var ul = $("#userSchedules").empty();
if (apptPortlet.ableToEdit) {
ul.append($("<li>").append($("<a href='#' class='activeItem apptStrong'>").html(apptPortlet.name.full).click(function (e) { e.preventDefault(); controller.transitionTo('userSchedule', apptPortlet.id); })));
$(".rg-sidebar").show();
}
$.get('rpc/appointmentsInfo/GetMySchedules/', function (schedules) {
if (schedules == null) return;
for (var key in schedules) {
ul.append($("<li>").append($("<a href='#' class='activeItem apptStrong'>").data('id',key).html(schedules[key]).click(function (e) { e.preventDefault(); controller.transitionTo('scheduleResource', $(this).data('id')); })));
}
if (schedules.length > 0)
$(".rg-sidebar").show();
});
}
});
function bindHelpText(g11n, screen) {
$(".apptHelpWrapper").appointmentHelp({ g11n: g11n, isHost: apptPortlet.ableToEdit, portletId:apptPortlet.portletId, screen: screen });
}
}
I briefly used Ember 1.7 but only ever with ember-cli. Anyway, I can point out a couple of things I am pretty sure that you aren't doing correctly. First off:
I changed all instances of the code where it was using
Ember.View.extend to Ember.Controller.extend
This does not make any sense. These are not comparable. If you meant Ember.Component that would make more sense but there's still not a 1:1 similarity. I would recommend studying the Ember.View docs from 1.7 as well as that for components and controllers. You should also give a the Ember.View deprecation guide a read through. The recommended upgrade path is to convert views to components, but components are isolated contexts unlike Ember.View. I think you will have to pass the controller to the Ember.Component instance (would be better to pass the properties needed). Since Ember.Component extends Ember.View, you might not be able to pass via the controller property directly (I don't know if this would be problematic but I would probably avoid).
Accessing data via {{view.someProp}} or {{controller.thisThing}} can nearly always be replaced by proper use of data passing and block params. See the guide on differences in yielded blocks for a complete example of using block params over the {{view}} keyword.
I would recommend going all the way through the deprecations guide to understand what needs to change.

Ember calculated property is recalculated without its dependencies changed

I have an calculated property(named userFields) depending on another calculated property(named userList). When the object(it's a view) is initialised, I found the property "userFields" was calculated hundreds of times with "userList" calculated only once, according to the console log. I don't know why does this happened.
Here are my codes:
App.MainServiceInfoApplicationQueueUserGroupSelectView = Ember.View.extend({
templateName: require('templates/main/service/info/applicationqueues/user_group_select'),
userCollapse: false,
groupCollapse: false,
toggleUserCollapse: function() {
myview = this;
this.set('userCollapse', !this.get('userCollapse'));
},
toggleGroupCollapse: function() {
this.set('groupCollapse', !this.get('groupCollapse'));
},
userList: function() {
console.log('calc user list'); // This is printed only once
var list = [];
App.User.find().forEach(function(item) {
list.push(item);
});
return list;
}.property('App.User.find()'),
groupList: function() {
var list = [];
App.Resourcegroup.find().forEach(function(item) {
list.push(item);
});
return list;
}.property('App.Resourcegroup.find()'),
userFields: function() {
console.log('calc user fields'); // This is printed hundreds of times
// Parse value
var parsedValues = [];
try {
var usersFromValue = this.get('value').split(' ')[0].split('/');
for (var i = 0; i < usersFromValue.length; i++)
parsedValues.push(usersFromValue[i]);
} catch (e) {}
var fields = [];
for (var i = 0; i < this.get('userList').length; i++) {
var item = this.get('userList')[i];
fields.push(Ember.Object.create({
viewClass: Ember.Checkbox.extend({
value: false,
checkedBinding: 'value'
}),
displayName: item.get('userName'),
name: item.get('userName'),
value: parsedValues.contains(item.get('userName'))
}));
}
return fields;
}.property('userList'),
groupFields: function() {
// Parse value
var parsedValues = [];
try {
var groupsFromValue = this.get('value').split(' ')[1].split('/');
for (var i = 0; i < groupsFromValue.length; i++)
parsedValues.push(groupsFromValue[i]);
} catch (e) {}
var fields = [];
for (var i = 0; i < this.get('groupList').length; i++) {
var item = this.get('groupList')[i];
fields.push(Ember.Object.create({
viewClass: Ember.Checkbox.extend({
value: false,
checkedBinding: 'value'
}),
displayName: item.get('groupName'),
name: item.get('groupName'),
value: parsedValues.contains(item.get('groupName'))
}));
}
return fields;
}.property('groupList'),
users: function() {
console.log('calc users'); // This is printed as many times as 'calc user fields' was printed
var list = [];
for (var i = 0; i < this.get('userFields').length; i++) {
var theField = this.get('userFields')[i];
if (parseBoolean(theField.get('value')) == true) list.push(theField.get('name'));
}
return list;
}.property('userFields, userFields.#each.value'),
groups: function() {
var list = [];
for (var i = 0; i < this.get('groupFields').length; i++) {
var theField = this.get('groupFields')[i];
if (parseBoolean(theField.get('value')) == true) list.push(theField.get('name'));
}
return list;
}.property('groupFields, groupFields.#each.value'),
usersString: function() {
return this.get('users').join(', ');
}.property('users'),
groupsString: function() {
return this.get('groups').join(', ');
}.property('groups'),
usersValue: function() {
return this.get('users').join('/');
}.property('users'),
groupsValue: function() {
return this.get('groups').join('/');
}.property('groups'),
value: function() {
return this.get('usersValue') + " " + this.get('groupsValue');
}.property('usersValue', 'groupsValue')
});

can I change rest model state without using .set()

I have model with custom attribute(array of objects). Like this
App.Adapter.registerTransform('images', {
serialize: function(value) {
var ret = []
value.forEach(function(img){
ret.pushObject(img.get('uuid'))
})
if (ret.get('length')) {
return ret.join(',')
} else
return false
},
deserialize: function(value) {
ret = []
if (typeof value !== 'undefined') {
uuids = value.split(',')
for (var i = 0; i < uuids.length; i++) {
var id = uuids[i]
ret.pushObject( App.Image.create({'uuid': id}) )
}
}
return ret
}
})
And my model.
App.Item = DS.Model.extend({
…
images: DS.attr('images')
})
in controller I need commit data, after pushing changes in this property. What I need to do for this case?
uploadImage: function(){
var self = this
uploading.done(function(result) {
self.get('images').pushObject(App.Image.create({uuid:result.uuid}))
console.log(self.get('isDirty')) // false
self.get('store').commit() //nothing to change
}).fail(function(result) {
…
}).always(function() {
…
})
},
Have you tried to do this?
self.notifyPropertyChange('images');

Backbone.js results of fetch doubling

I am trying to use Django and tastypie with backbone.js and mustache. I have set up an example to study those. When using the below code I get results of users doubling as:
-Id User name
-1 yol
-2 dada
-1 yol
-2 dada
--- MY CODE ---
// I think this tastypie adjustment is not related with the problem but i want you to see the //whole code
window.TastypieModel = Backbone.Model.extend({
base_url: function() {
var temp_url = Backbone.Model.prototype.url.call(this);
return (temp_url.charAt(temp_url.length - 1) == '/' ? temp_url : temp_url+'/');
},
url: function() {
return this.base_url();
}
});
window.TastypieCollection = Backbone.Collection.extend({
parse: function(response) {
this.recent_meta = response.meta || {};
return response.objects || response;
}
});
(function($){
// MODELS-COLLECTIOS
//USERS
var User = TastypieModel.extend({
url: USERS_API
});
var Users = TastypieCollection.extend({
model: User,
url:USERS_API
});
//VIEWS
var UsersView = Backbone.View.extend({
render: function(){
// template with ICanHaz.js (ich)
this.el = ich.userRowTpl(this.model.toJSON());
return this;
}
});
//main app
var AppView = Backbone.View.extend({
tagName: 'tbody',
initialize: function() {
this.users = new Users();
this.users.bind('all', this.render, this);
this.users.fetch();
},
render: function () {
// template with ICanHaz.js (ich)
this.users.each(function (user) {
$(this.el).append(new UsersView({model: user}).render().el);
}, this);
return this;
}
});
var app = new AppView();
$('#app').append(app.render().el);
})(jQuery);
I would say you are firing two times the render, because your view is listening to all events, try instead to bind it just to reset and see how it goes:
initialize: function() {
this.users = new Users();
this.users.bind('reset', this.render, this);
this.users.fetch();
},