Angularjs Error: [ngRepeat:dupes] in ng-options - javascript

Hello I'm making a code to study in angularjs and found the error.
Error: [ngRepeat:dupes]
http://errors.angularjs.org/1.6.4/ngRepeat/dupes?p0=cursostable%20in%20cursos%20%7C%20filter%3ApesquisaCurso&p1=object%3A3&p2=%7B%22codigo%22%3A45434%2C%22descricao%22%3A%22java%20web%22%2C%22datahorario%22%3A%22Segundas%20e%20Sextas%2C%2019hrs%22%2C%22professor%22%3A%7B%22codigo%22%3A1%2C%22nome%22%3A%22asasasasasa%22%2C%22email%22%3A%22asasasas%40hotmail.com%22%2C%22fone%22%3A%222323232323%22%7D%2C%22%24%24hashKey%22%3A%22object%3A3%22%7D
in console This error prevents me from entering new record
code below:
html
<div class="form-group">
<label for="professor" class="col-sm-1">Professor</label>
<div class="col-sm-10">
<select class="form-control" id="curso.professor"ng-model="curso.professor"
ng-options="professor.nome for professor in professores track by professor.codigo">
</select>
</div>
</div>
<button type="button" ng-click="salvar()" ng-disabled="!curso.codigo || !curso.descricao || !curso.datahorario || !curso.professor" class="btn btn-success">Cadastrar</button>
controller
cursoModulo.controller("cursoController", function($scope){
$scope.professores = [
{codigo: 1, nome: 'asasasasasa', email: 'asasasas#hotmail.com', fone:'2323232323'},
];
$scope.cursos = [
{codigo: 45434, descricao: 'java web', datahorario: 'Segundas e Sextas, 19hrs', professor: {codigo: 1, nome: 'asasasasasa', email: 'asasasas#hotmail.com', fone:'2323232323'}},
];
$scope.selecionaCurso = function(cursoSelecionado){
$scope.curso = cursoSelecionado;
}
$scope.limparCampo = function(){
$scope.curso = null;
}
$scope.salvar = function(){
$scope.cursos.push($scope.curso);
$scope.limparCampo();
}
$scope.excluir = function(){
$scope.cursos.splice($scope.cursos.indexOf($scope.curso),1);
$scope.limparCampo();
}

I suppose, new record has a such "codigo" that already presents in the "professores" list. Rememeber that all records in angular collections must have uniq field that you define in "track by" expression

It won't work if you are using angular version < 1.2.0
Change your version to (minimum of) 1.2 and it will work, since "track by" was introduced in that version.
Your code work on this fiddle (jsfiddle.net/JKBbV/1370) with angular 1.6.4

AngularJS does not allow duplicates in a ng-repeat directive.
That means whatever you are writing in track by should be unique so try track by $index instead of track by professor.codigo as said by rrd.
Working Plnkr
Source: click here!

Related

AngularJS - ngRepeat and ngMessages

I struggle to make ngMessages work in a ngRepeat loop. Please consider the following example :
<form name="$ctrl.demoForm.$fc" novalidate>
<div ng-repeat="tag in $ctrl.demoForm.tags track by $index">
<div>
<label>Tag:</label>
<input name="tag{{$index}}" ng-model="tag.value" type="text" ng-pattern="/^[a-z]*$/">
<button ng-click="$ctrl.removeTag($index)">Remove</button>
</div>
<ng-messages for="$ctrl.demoForm.$fc['tag'+$index].$error">
<ng-message when="pattern">Must only contain letters.</ng-message>
</ng-messages>
</div>
<button ng-click="$ctrl.addTag()">Add new tag</button>
</form>
I simply iterate over an array of tags stored in $ctrl.demoForm.tags. I'm aware that ng-repeat creates a new scope each iteration so each tag is an object like {value: 'tag value'}.
Here is the controller associated, very basic stuff:
app.controller('DemoCtrl', function() {
this.demoForm = {
tags: [
{value: 'tag 1'},
{value: 'tag 2'}
]
};
this.addTag = function(){
this.demoForm.tags.push({value: ''});
};
this.removeTag = function(index) {
if (this.demoForm.tags.length > index) {
this.demoForm.tags.splice(index, 1);
}
};
});
It works fine, I can add and remove tags normally. But, problems arise when a field has an error. If you try to remove a field above the field on error, their values get messed up.
The odd thing is that the good field is actually removed, only their values seems desynchronized when on error. I added an id attribute in the jsbin to illustrate the problem, you can find it here :
http://jsbin.com/nifipatojo/edit?html,js,output
Does anyone have an idea of what happen ?
Thanks for your help.

Understanding scope, ng-click and the angular-way

While working on the phone tutorial i wondered how to implement this use case
user clicks on add phone
the function addItem is fired and the phone.id is passed
the relevant phone is retrieved and the quantity increased by 1
the increased quantity should be displayed in the input
You can find my codepen demo here and this is the relevant code
<ul class="phones">
<li ng-repeat="phone in phones | filter:query | orderBy:orderProp">
<b>{{phone.name}} </b>
<i ng-click="addItem(phone.id)"> add phone</i>
<input name='{{phone.id}}'
value='{{phone.qty}}'
ng-readonly='{{phone.orderReadonly}}' /><br />
<p>{{phone.snippet}} </p>
</li>
</ul>
and the javascript
var phonecatApp = angular.module('phonecatApp', []);
phonecatApp.controller('PhoneListCtrl', function($scope) {
$scope.phones = [
{'id': 1, 'name': 'Mui 1'
,'snippet': 'Our newcomer from asia.'
,'orderReadonly' : 'false', 'qty': 4}
....
,{'id': 4, 'name': 'Msft Lumiaâ„¢'
,'snippet': 'Who knows what windows 10 will bring'
,'orderReadonly' : 'true','qty': 2}
];
$scope.orderProp = 'id';
$scope.addItem = function(phone_id) {
// from http://stackoverflow.com/questions/15610501/
var found = $filter('filter')($scope.phones, {id: phone_id}, true);
if (found.length) {
found[0].qty = found[0].qty + 1;
} else {
$scope.selected = 'Not found';
}
}
});
Current status
passing the id works
finding the phone does not work: var found = $filter('filter')($scope.phones, {id: phone_id}, true); // found in http://stackoverflow.com/questions/15610501/
increasing quantity does not work
My questions are
if and how onclick / ng-click should be used in the angular way
how to solve my requirement - increase phone quantity onclick on <i>add phone</i>
I don't know why qty doesn't work - it should, unless your filter doesn't find a match.
But you shouldn't even be doing this. Instead of passing the id of the object and then locating the object to change its property, just pass the object phone itself:
<i ng-click="addItem(phone)"> add phone</i>
Then, in the controller, simply do this:
$scope.addItem = function(phone) {
phone.qty = phone.qty + 1;
}
Summarising the two above answers. The "++" increment will not work on the variable or object property from the "ng-click" directive, so instead you should use:
variable = variable + 1
And in connection to the original question the
<i ng-click="phone.qty = phone.qty + 1"> add phone</i>
will do the trick.
To answer your first question:
Using ng-click runs an angular expression inside Angular's scope. If you use the onclick simply runs javascript code.
So if you have some variable 'numPhones' initialized inside your controller, then you can have:
ng-click="numPhones = numPhones + 1"
and the numPhones variable will be incremented.
On the other hand:
onclick="numPhones = numPhones + 1"
doesn't reference the surrounding angular scope.
So if you're using Angular, you probably wouldn't want onclick at all.
Here's an example:
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script>
<script>
angular.module('phones', [])
</script>
</head>
<body ng-app='phones'>
<div>
{{ numPhones }}
<button ng-click="numPhones = numPhones + 1"> add 1</button>
</div>
</body>
</html>

Add dynamic model to newly created elements via directives in angularjs

Following is my PLNKR CODE which is working fine.
Problem - I need to add dynamic scope to these element so that I can grab the contact number + type.
I google the problem before asking but as I am new to directives in angular I am confused with the results, let me know what else I need to add to grab the result.
Following kind of result I am expecting -
contact: [
{number: 56432452, type: "Cell"},
{number: 67895644, type: "Work"},
{number: 78943245, type: "Cell"},
{number: 66793456, type: "Home"},
{number: 90546675, type: "Fax"},
];
Also, I need to use the same form in EDIT mode, let me know what are the extra things that I need to keep in mind while developing this functionality for the edit case.
Following is my directive code -
<div class="form-group">
<label class="col-sm-2 control-label">Contact Number<span class="asterisk">*</span></label>
<div class="col-sm-5">
<input type="text" class="form-control">
</div>
<div class="col-sm-2">
<select class="btn">
<option>Cell</option>
<option>Work</option>
<option>Home</option>
<option>Fax</option>
</select>
</div>
<div class="col-sm-1">
<img src="http://img.informer.com/icons/png/16/3225/3225535.png" class="remCls">
</div>
</div>
As you can see currently the select and input do not contain and ngModel. Let me know how do I introduce this to obtain the above mentioned result.
I'm not sure this is what you need but I think you could define your controller as:
myApp.controller("myCtrl", function($scope){
//Create and array of contacts in your model
$scope.contacts = [];
//Add a new contact to the model
$scope.addContact = function() {
var contacts = $scope.contacts;
contacts[contacts.length] = {};
}
//Remove a contact from the model based on its index
$scope.removeContact = function(index) {
$scope.contacts.splice(index, 1);
}
});
Then on your HTML, you leverage the Angular directives ng-repeat and ng-click:
<body ng-controller="myCtrl">
<button ng-click="addContact()"> Add Contact </button>
<div class="form-group" ng-repeat="contact in contacts">
<label>Contact Number</label>
<input type="text" ng-model="contact.contact">
<select ng-model="contact.type">
<option>Cell</option>
<option>Work</option>
<option>Home</option>
<option>Fax</option>
</select>
<button ng-click="removeContact($index)"> Remove Contact </button>
</div> <!-- Close Repeater -->
</body>
Here's your PLNKR link with the changes proposed:
http://plnkr.co/edit/VWCdXSnOsY18XoCKxO0t?p=preview
First of all I would like to thank ExpertSystem for suggesting me to think in Angular way. Then I would like to thank Foxandxss and medice from angular IRC for making the things right not by code but improving my concept and approach for angular.
This is the WORKING code, I came up with for the above problem.
Actually I don't need directive and managed things easily without it.
medice: directives are fine, but when you set up click events that
modify dom, it's gonna break
medice: angularjs can't bind directives properly
Following is my controller code -
var myApp = angular.module("myApp", []);
myApp.controller("myCtrl", function($scope){
$scope.cnctnum = [];
$scope.cncttype = [];
$scope.types = [
{name: "Cell", value: 1},
{name: "Work", value: 2},
{name: "Home", value: 3},
{name: "Fax", value: 4}
];
$scope.items = [];
var i =0;
$scope.addCnt = function(){
$scope.items.push(i);
i++;
};
$scope.remCl = function(index){
$scope.cnctnum.splice(index, 1);
$scope.cncttype.splice(index, 1);
$scope.items.splice(index, 1);
};
$scope.getval = function(){
console.log($scope.cnctnum);
console.log($scope.cncttype);
};
});

Angular ng-class performance issue when too many elements in DOM

I have been working on a complex angular page which has been causing performance issue. To highlight the problem I have created a fiddle http://jsfiddle.net/4ex2xgL1/3/ here.
Essentially the performance issue is being caused by ng-class statement which has a function in it.
<span class="done-{{todo.done}}" ng-class="myfunction()">{{todo.text}}</span>
The span is in an ng-repeat. On running the fiddle one can see that ng-class gets executed several times when the page loads and on each key up it gets called as many time as number of items in the TODO list.
This is a lot simpler case, in my case I have 780 items on my page and the function ends up being evaluated aroung 3000 times!
One of the solution we saw is to break up the scope but it will cause almost a rewrite of my app.
We also tried https://github.com/Pasvaz/bindonce but it doesn't seem to be working with highly dynamic content.
Any thoughts?
I built a tree with https://github.com/JimLiu/angular-ui-tree with almost 500 items to render, with quite a lot of listeners. It takes 5 seconds to render. Bindonce won't work there.
The only solution out there is make ng-repeat do less. Keep the list small with a pagination, search or anything. Its the best shot as far as I know.
Well here are my recommendations
use ng-change on the checkbox to manipulate dom or anything rather using ng-class, it will improve your performance drastically.
<li ng-repeat="todo in todos track by todo.id">
<input type="checkbox" ng-model="todo.done" ng-change="myfunction()">
<span class="done-{{todo.done}}">{{todo.text}}</span>
</li>
http://jsfiddle.net/4ex2xgL1/3/
use track by in ng-repeat if you have ids, more here http://www.codelord.net/2014/04/15/improving-ng-repeat-performance-with-track-by/
dont show 780 items in a list. Use a searchbox to show some 100 or 50 or you know better
quick-ng-repeat not used yet, try testing it https://github.com/allaud/quick-ng-repeat
finally a few good http://tech.small-improvements.com/2013/09/10/angularjs-performance-with-large-lists/
Finally I found the solution and it will helps lot to improve performance in angular js.
If your model changes dynamically and if you have lots of data and then also it improve AngularJS pages rendering up to 1000% and more - no kidding !.
Fore more information you can visit : http://orangevolt.blogspot.in/2013/08/superspeed-your-angularjs-apps.html
Follow the steps:
download the library from the link:library
2.example without library:(check your console)
function MyController( $scope) {
var entries = [
{ label : 'one', value : 'first entry'},
{ label : 'two', value : 'second entry'},
{ label : 'three', value : 'third entry'}
];
$scope.label ="";
$scope.value ="";
$scope.order = 'label';
$scope.add = function() {
entries.push({
label : $scope.label,
value : $scope.value
});
};
$scope.getEntries = function() {
console && console.log( "getEntries() called");
return entries;
};
}
<script src="https://raw.githubusercontent.com/lodash/lodash/2.4.1/dist/lodash.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.0/jquery.min.js"></script>
<form name="myform" ng-app ng-controller="MyController">
Label/Value :
<input type="text" required ng-model="label">
<input type="text" required ng-model="value">
<button
ng-disabled="!myform.$valid"
ng-click="add()"
>Add</button>
<fieldset>
<legend>
Entries sorted by
<select
ng-model="order"
ng-options="property for property in [ 'label', 'value']">
</select>
</legend>
<div ng-repeat="entry in getEntries() | orderBy:order">
{{entry.label}} = "{{entry.value}}"
</div>
</fieldset>
</form>
3.example with library:(check your console)
function MyController( $scope) {
var entries = [
{ label : 'one', value : 'first entry'},
{ label : 'two', value : 'second entry'},
{ label : 'three', value : 'third entry'}
];
$scope.label ="";
$scope.value ="";
$scope.order = 'label';
$scope.add = function() {
entries.push({
label : $scope.label,
value : $scope.value
});
// clear cache
$scope.getEntries.cache = {};
};
$scope.getEntries = _.memoize(
function() {
console && console.log( "getEntries() sorted by '" + $scope.order + " 'called");
// return entries sorted by value of $scope.order
return _.sortBy( entries, $scope.order);
},
function() {
// return the cache key for the current result to store
return $scope.order;
}
);
}
<script src="https://raw.githubusercontent.com/lodash/lodash/2.4.1/dist/lodash.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.20/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.0/jquery.min.js"></script>
<form name="myform" ng-app ng-controller="MyController">
Label/Value :
<input type="text" required ng-model="label">
<input type="text" required ng-model="value">
<button
ng-disabled="!myform.$valid"
ng-click="add()"
>Add</button>
<fieldset>
<legend>
Entries sorted by
<select
ng-model="order"
ng-options="property for property in [ 'label', 'value']">
</select>
</legend>
<div ng-repeat="entry in getEntries()">
{{entry.label}} = "{{entry.value}}"
</div>
</fieldset>
</form>

Similar functionality as in Dev HTTP Client using AngularJS

Right now I am working with AngularJS on a web interface which should have similar behavior like Dev HTTP Client. I can't find a way how to add headers in the way like DHC does.
I'm trying to make it somehow like this, but it isn't working since array is initialized empty:
<div ng-repeat="header in headersCollection.headers">
<input ng-model="header.name" type="text"/> :
<input ng-model="header.value" type="text"/>
</div>
<button type="button" ng-click="addNewHeader()">Add</button>
Headers should be stored inside this object and be available for creating, editing and removing through web interface. Just like in DHC.
$rootScope.headersCollection = {
headers : []
}
Any idea / link / answer are highly appreciated and answered immidiately.
Thank you.
Just make an "empty" header object in the headers collection. See http://jsfiddle.net/e8MEx/
Of course you will want to throw in some validation to make sure they are values before adding another one and potentially add the ability to remove an item:
JavaScript:
var mod = angular.module("myApp", []);
mod.run(["$rootScope", function($rootScope) {
//start the array with one empty value for header
$rootScope.headersCollection = {
headers : [{name: "", value: ""}]
}
}]);
mod.controller("MainController", ["$scope", "$rootScope", function ($scope, $rootScope) {
$scope.headersCollection = $rootScope.headersCollection
$scope.addNewHeader = function () {
//push a new empty value onto the array.
$scope.headersCollection.headers.push({name: "", value: ""});
}
}]);
HTML:
<div ng-app="myApp" ng-controller="MainController">
<div ng-repeat="header in headersCollection.headers">
<input ng-model="header.name" type="text"/> :
<input ng-model="header.value" type="text"/>
</div>
<button type="button" ng-click="addNewHeader()">Add</button>
<p>{{headersCollection.headers}}</p>
</div>

Categories

Resources