I have a HTML code like below which I use AngularJS framework within it:
<select name="choose-staff" ng-model="admin_times[0].user" ng-change="update(reserve.staff)" id="choose-staff">
<option ng-repeat="value in staff | unique:'employee.user.username'" value="{[{ value.employee.user.username }]}">{[{ value.employee.user.first_name }]} {[{ value.employee.user.last_name }]}</option>
</select>
And I get an error like this:
Duplicates in a repeater are not allowed. Use 'track by' expression to specify unique keys. Repeater: value in staff | unique:'employee.user.username', Duplicate key: string:ب, Duplicate value: ب
And if I use track by $index it destroys my desired structure and when I click one of options, the rest of them get vanished.
[
{
"employee": {
"user": {
"id": 3,
"first_name": "اشکان",
"last_name": "وکیلی",
"user_profile": null,
"username": "ashkan"
},
"business": {
"id": "caf241cd-adb4-44ee-8c40-0f6cdb3bc5ac",
"fa_name": "ساینا",
"en_name": "Saina",
"service": [],
"persian_address": "",
"location": "35.77885523664743,51.39051060551765",
"avatar": null,
"email": ""
},
"is_head": true
},
"service": {
"en_title": "Haircut",
"fa_title": "کوتاهی مو"
},
"allocated_time": 60,
"booked_no": "XG4OCX81"
},
{
"employee": {
"user": {
"id": 3,
"first_name": "اشکان",
"last_name": "وکیلی",
"user_profile": null,
"username": "ashkan"
},
"business": {
"id": "caf241cd-adb4-44ee-8c40-0f6cdb3bc5ac",
"fa_name": "ساینا",
"en_name": "Saina",
"service": [],
"persian_address": "",
"location": "35.77885523664743,51.39051060551765",
"avatar": null,
"email": ""
},
"is_head": true
},
"service": {
"en_title": "Color",
"fa_title": "رنگ مو"
},
"allocated_time": 25,
"booked_no": "1AY3F24G"
},
{
"employee": {
"user": {
"id": 2,
"first_name": "رضا",
"last_name": "ولیمرادی",
"user_profile": {
"id": "9d9be03a-f840-46ea-a21e-76cd5775a886",
"avatar": null,
"city": "",
"gender": "F",
"birthday": null,
"country": "IR",
"about": "",
"timestamp": "2015-11-06T14:56:10.312340Z",
"location": "36.03133177633187,51.328125"
},
"username": "reza"
},
"business": {
"id": "caf241cd-adb4-44ee-8c40-0f6cdb3bc5ac",
"fa_name": "ساینا",
"en_name": "Saina",
"service": [],
"persian_address": "",
"location": "35.77885523664743,51.39051060551765",
"avatar": null,
"email": ""
},
"is_head": false
},
"service": {
"en_title": "Yellow",
"fa_title": "زرد"
},
"allocated_time": 15,
"booked_no": "H989M93X"
},
{
"employee": {
"user": {
"id": 1,
"first_name": "علیرضا",
"last_name": "غفاری",
"user_profile": {
"id": "884b36e3-7bad-466f-afee-25801572b834",
"avatar": null,
"city": "",
"gender": "F",
"birthday": null,
"country": "IR",
"about": "",
"timestamp": "2015-11-06T14:56:39.522362Z",
"location": "32.24997445586331,53.26171875"
},
"username": "alireza"
},
"business": {
"id": "caf241cd-adb4-44ee-8c40-0f6cdb3bc5ac",
"fa_name": "ساینا",
"en_name": "Saina",
"service": [],
"persian_address": "",
"location": "35.77885523664743,51.39051060551765",
"avatar": null,
"email": ""
},
"is_head": true
},
"service": {
"en_title": "Color",
"fa_title": "رنگ مو"
},
"allocated_time": 20,
"booked_no": "O5KLFPZB"
}
]
I don't like the redundancy of employee.user.username
Looks to me like the unique value in each object is the booked_no.
In which case you should use track by value.booked_no
I have an backbone application that collects data from an api the data from the api looks like this,
{
"id": "117",
"name": "Another new organisation",
"slug": "another-new-organisation",
"information": "",
"type": "organisation",
"notifications": "0",
"add_all": "0",
"created_at": "2015-01-13 17:29:45",
"updated_at": "2015-01-13 17:29:45",
"projects": [
{
"id": "131",
"name": "sdasdasdas",
"description": null,
"total_cost": "12312.00",
"start_date": "2015-01-14",
"finish_date": "2015-01-23",
"status": "1",
"sales_person": null,
"project_manager": null,
"client_id": "0",
"organisation_id": "117",
"owner_id": null,
"user_id": "1",
"created_at": "2015-01-28 18:36:55",
"updated_at": "2015-01-28 18:36:55",
"pivot": {
"organisation_id": "117",
"project_id": "131"
},
"clients": null
},
{
"id": "132",
"name": "another test",
"description": null,
"total_cost": "23131.00",
"start_date": "2015-01-07",
"finish_date": "2015-01-16",
"status": "1",
"sales_person": null,
"project_manager": null,
"client_id": "0",
"organisation_id": "117",
"owner_id": null,
"user_id": "1",
"created_at": "2015-01-28 18:38:45",
"updated_at": "2015-01-28 18:38:45",
"pivot": {
"organisation_id": "117",
"project_id": "132"
},
"clients": null
},
{
"id": "133",
"name": "yest another test",
"description": null,
"total_cost": "99999999.99",
"start_date": "0000-00-00",
"finish_date": "0000-00-00",
"status": "1",
"sales_person": null,
"project_manager": null,
"client_id": "0",
"organisation_id": "117",
"owner_id": null,
"user_id": "1",
"created_at": "2015-01-28 18:39:25",
"updated_at": "2015-01-28 18:39:25",
"pivot": {
"organisation_id": "117",
"project_id": "133"
},
"clients": null
},
{
"id": "134",
"name": "dsadasdasdassas",
"description": null,
"total_cost": "23213.00",
"start_date": "2015-01-21",
"finish_date": "2015-01-29",
"status": "1",
"sales_person": null,
"project_manager": null,
"client_id": "0",
"organisation_id": "117",
"owner_id": null,
"user_id": "1",
"created_at": "2015-01-28 18:40:58",
"updated_at": "2015-01-28 18:40:58",
"pivot": {
"organisation_id": "117",
"project_id": "134"
},
"clients": null
},
{
"id": "135",
"name": "wewqeqweqw",
"description": null,
"total_cost": "33432.00",
"start_date": "2015-01-14",
"finish_date": "2015-01-31",
"status": "1",
"sales_person": null,
"project_manager": null,
"client_id": "0",
"organisation_id": "117",
"owner_id": null,
"user_id": "1",
"created_at": "2015-01-28 18:43:03",
"updated_at": "2015-01-28 18:43:03",
"pivot": {
"organisation_id": "117",
"project_id": "135"
},
"clients": null
},
{
"id": "136",
"name": "testing save",
"description": null,
"total_cost": "12321.00",
"start_date": "2015-01-06",
"finish_date": "2015-01-23",
"status": "1",
"sales_person": null,
"project_manager": null,
"client_id": "0",
"organisation_id": "117",
"owner_id": null,
"user_id": "1",
"created_at": "2015-01-28 18:46:56",
"updated_at": "2015-01-28 18:46:56",
"pivot": {
"organisation_id": "117",
"project_id": "136"
},
"clients": null
},
{
"id": "137",
"name": "Testing again",
"description": null,
"total_cost": "23131.00",
"start_date": "2015-01-13",
"finish_date": "2015-01-29",
"status": "1",
"sales_person": null,
"project_manager": null,
"client_id": "0",
"organisation_id": "117",
"owner_id": null,
"user_id": "1",
"created_at": "2015-01-28 18:47:28",
"updated_at": "2015-01-28 18:47:28",
"pivot": {
"organisation_id": "117",
"project_id": "137"
},
"clients": null
}
],
"clients": [
{
"id": "67",
"name": "Boom a client!",
"information": "",
"address": null,
"website": null,
"email": null,
"phone": null,
"type": "client",
"add_all": "0",
"created_at": "2015-01-28 17:49:43",
"updated_at": "2015-01-28 17:49:43",
"user_id": "1",
"owner_id": "117",
"projects": [],
"users": []
},
{
"id": "66",
"name": "New client",
"information": "",
"address": null,
"website": null,
"email": null,
"phone": null,
"type": "client",
"add_all": "0",
"created_at": "2015-01-27 12:27:59",
"updated_at": "2015-01-27 12:27:59",
"user_id": "1",
"owner_id": "117",
"projects": [],
"users": []
},
{
"id": "71",
"name": "sadasdasdas",
"information": "",
"address": null,
"website": null,
"email": null,
"phone": null,
"type": "client",
"add_all": "0",
"created_at": "2015-01-28 17:58:57",
"updated_at": "2015-01-28 17:58:57",
"user_id": "1",
"owner_id": "117",
"projects": [],
"users": []
},
{
"id": "68",
"name": "Saving a client",
"information": "",
"address": null,
"website": null,
"email": null,
"phone": null,
"type": "client",
"add_all": "0",
"created_at": "2015-01-28 17:50:31",
"updated_at": "2015-01-28 17:50:31",
"user_id": "1",
"owner_id": "117",
"projects": [],
"users": []
},
{
"id": "72",
"name": "Saving now?",
"information": "",
"address": null,
"website": null,
"email": null,
"phone": null,
"type": "client",
"add_all": "0",
"created_at": "2015-01-28 18:02:47",
"updated_at": "2015-01-28 18:02:47",
"user_id": "1",
"owner_id": "117",
"projects": [],
"users": []
},
{
"id": "70",
"name": "What gets returned and not saved?",
"information": "",
"address": null,
"website": null,
"email": null,
"phone": null,
"type": "client",
"add_all": "0",
"created_at": "2015-01-28 17:57:40",
"updated_at": "2015-01-28 17:57:40",
"user_id": "1",
"owner_id": "117",
"projects": [],
"users": []
},
{
"id": "69",
"name": "What gets returned?",
"information": "",
"address": null,
"website": null,
"email": null,
"phone": null,
"type": "client",
"add_all": "0",
"created_at": "2015-01-28 17:56:09",
"updated_at": "2015-01-28 17:56:09",
"user_id": "1",
"owner_id": "117",
"projects": [],
"users": []
}
],
"users": [
{
"id": "1",
"email": "xxxxxxxxxxxxxx",
"first_name": "xxxxxxxxxxx",
"last_name": "xxxxxxxxxxx",
"display_name": "xxxxxxxxxxxxx",
"initials": "SA",
"remember_me": null,
"active": "1",
"invite_code": null,
"default_organisation": "114",
"forgotten_code": "7bffdaa1b5b238f5ba8b13e46c53dc46",
"login_type": "normal",
"api_token": null,
"created_at": "-0001-11-30 00:00:00",
"updated_at": "2015-01-28 10:48:41",
"deleted_at": null,
"pivot": {
"organisation_id": "117",
"user_id": "1",
"is_admin": "0"
}
},
{
"id": "85",
"email": "richard#xxxxxxxxxx",
"first_name": "xxxxxx",
"last_name": "xxxxxxx",
"display_name": "xxxxxxxxxxx",
"initials": "RB",
"remember_me": null,
"active": "1",
"invite_code": null,
"default_organisation": null,
"forgotten_code": null,
"login_type": "normal",
"api_token": null,
"created_at": "-0001-11-30 00:00:00",
"updated_at": "-0001-11-30 00:00:00",
"deleted_at": null,
"pivot": {
"organisation_id": "117",
"user_id": "85",
"is_admin": "1"
}
}
]
}
I would have thought that some along the lines of this structure would be returned from my backbone model,
attributes: Object
add_all: "0"
clients: s
created_at: "2014-12-16 10:16:03"
group_name: ""
id: "114"
information: ""
members: s
name: "Company Name"
notifications: "0"
projects: s
slug: "company-name"
teams: s
type: "organisation"
updated_at: "2015-01-29 16:04:48"
users: Array[2]
But instead I am getting the following,
What would be causing this? I read somewhere that Backbone does like receiving ID's that are not sequential could that be it? Here is my model code,
'use strict'
App.Models.Client = Backbone.Model.extend({
urlRoot: "http://" + App.API_ROOT + "/clients ",
defaults: {
type:'client'
},
initialize: function() {
var members = this.get('users');
//console.log(members);
var ownerUser = this.get('owner_user');
var ownerOrganisation = this.get('owner_organisation');
var projects = this.get('projects');
this.set('members', new App.Collections.Users(members));
this.set('projects', new App.Collections.Projects(projects));
if(ownerOrganisation == null) {
this.set('owner', new App.Models.User(ownerUser));
} else {
this.set('owner', new App.Models.Organisation(ownerOrganisation));
}
},
});
So a view is created that display a list of "clients" (collection) that belong to "organisation" (model).
The organisation model looks like this,
'use strict'
App.Models.Organisation = Backbone.Model.extend({
urlRoot: "http://" + App.API_ROOT + "/organisations",
defaults: {
group_name: '',
type:'organisation'
},
initialize: function() {
//Gets
var members = this.get('users');
var projects = this.get('projects');
var teams = this.get('teams');
var clients = this.get('clients');
//Sets
if(members != undefined) {
this.set('members', new App.Collections.Users(members));
} else {
this.set('members', new App.Collections.Users);
}
if(projects != undefined) {
this.set('projects', new App.Collections.Projects(projects));
} else {
this.set('projects', new App.Collections.Projects);
}
if(teams != undefined) {
this.set('teams', new App.Collections.Teams(teams));
} else {
this.set('teams', new App.Collections.Teams);
}
if(clients != undefined) {
this.set('clients', new App.Collections.Clients(clients));
} else {
this.set('clients', new App.Collections.Clients);
}
},
});
And the clients collection looks like this,
App.Collections.Clients = Backbone.Collection.extend({
url: 'http://' + App.API_ROOT + '/clients',
model: App.Models.Client,
initialize: function() {
},
search: function( filterValue ) {
var filterThroughValue = function(data) {
filterValue = filterValue.toLowerCase();
return _.some(_.values(data.toJSON()), function(value) {
if(value != undefined) {
value = (!isNaN(value) ? value.toString() : value);
//console.log(value.toLowerCase().indexOf(filterValue));
return value.toLowerCase().indexOf(filterValue) >= 0;
}
});
};
return App.Collections.filterCollection = this.filter(filterThroughValue);
}
});
The data actually comes from the organisation root. And the view does all the work is here,
App.Views.ClientPanel = Backbone.View.extend({
tagName: 'div',
className: 'client-panel clearfix',
template: _.template( $("#tpl-client-panel").html() ),
events: {
"click .stacked-nav a" : "triggerHeight",
"click .js-add-client" : "addNewClient"
},
initialize: function(options) {
this.options = options;
this.model.get('clients').on('add', this.addNewClientList, this);
App.EVENTS.on("clientAdded", function(){ $(".nav-stacked li:last a").trigger('click') }, this);
},
render: function() {
this.$el.html( this.template() );
this.addClients();
App.EVENTS.trigger("listBuilt");
return this;
},
addClients: function() {
if(this.model.get('clients').length > 0) {
this.collection.each( this.addClient, this);
}
},
addClient: function(model) {
var client = new App.Views.SingleClientEntry({
model: model,
is_owner : this.options.is_owner,
currentOrganisation:this.model
});
this.$('.nav-stacked').append( client.render().el );
},
addNewClientList: function(model) {
if(model.get('owner_id') == this.model.get('id')) {
var client = new App.Views.SingleClientEntry({
model: model,
is_owner : this.options.is_owner,
currentOrganisation:this.model
});
this.$('.nav-stacked').append( client.render().el );
}
},
addNewClient: function(e) {
e.preventDefault();
//$(".js-create-group[data-type=client]").trigger('click');
this.clientModal = new App.Views.CreateClientView({
current_organisation: this.model.get('id')
});
this.clientModal.render();
}
});
App.Views.SingleClientEntry = Backbone.View.extend({
tagName: 'li',
className: 'organisation-client',
template: _.template( $("#tpl-client-nav-entry").html() ),
events: {
"click .js-change-client" : "changeClient"
},
initialize: function(options) {
this.options = options;
console.log(this.model);
this.model.on('change', this.render, this);
this.model.on('change', this.showActive, this);
this.model.on('destroy', this.removeView, this);
this.currentOrganisation = options.currentOrganisation;
},
render: function() {
this.$el.html( this.template({
client: this.model.toJSON(),
is_owner: this.options.is_owner
}));
return this;
},
showActive: function() {
this.$('a').addClass('active');
},
changeClient: function(e) {
e.preventDefault();
var element = $(e.currentTarget),
modelID = element.data('id');
$(".nav-stacked a.active").removeClass('active');
element.addClass('active');
var clientData = new App.Views.ClientData({
model: this.currentOrganisation,
modelID : modelID,
is_owner: this.options.is_owner
});
Pops.CurrentClientID = modelID;
$('.client-details').html( clientData.render().el );
$('.tertiary-tabs').find('li:first').find('a').trigger('click');
},
removeView: function() {
this.remove();
}
});