I have a simpe controller with its view, I am trying to add an item to the collection through ng-click, but I just started playing with angular and I don't see why the following view adding items is not working, however I hardcoded some test items and they display just fine, I would appreciate your help
<html data-ng-app>
<body>
<div data-ng-controller="ItemsController">
name : <input type="text" data-ng-model="newItem.name"/>
description : <input type="text" data-ng-model="newItem.description"/>
maintainer : <input type="text" data-ng-model="newItem.maintainer"/>
<button data-ng-click="addNew(newItem)">Add</button>
<ul>
<li data-ng-repeat="item in items">{{item.name}} {{item.description}} {{item.maintainer}}</li>
</ul>
</div>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.13/angular.min.js"></script>
<script type="text/javascript">
function ItemsController ($scope) {
$scope.items =
[{name:'x',description:"sss",maintainer:'me'},
{name:'y',description:"aaa",maintainer:'me'}];
var addNew = function(newItem)
{
$scope.items.push(newItem);
};
}
</script>
</body>
</html>
You need to add the addNew function to the scope object. If you change the:
var addNew = function(newItem)
{
$scope.items.push(newItem);
};
into
$scope.addNew = function(newItem)
{
$scope.items.push(newItem);
};
you'll see that it should work just fine.
Related
This question already has answers here:
Angular ng-repeat Error "Duplicates in a repeater are not allowed."
(10 answers)
Closed 4 years ago.
I am able to add the items (through html input) to un-ordered list dynamically through ng-click event handling. This happens whenever i change the input textbox value. But if i click the add button without updating the textbox, the input textbox value is not added to list.
<body>
<script>
var app = angular.module("myShoppingList", []);
app.controller("myCtrl", function($scope) {
$scope.products = ["Milk", "Bread", "Cheese"];
$scope.addItem = function () {
$scope.products.push($scope.addMe);
}
});
</script>
<div ng-app="myShoppingList" ng-controller="myCtrl">
<ul>
<li ng-repeat="x in products">{{x}}</li>
</ul>
<input ng-model="addMe">
<button ng-click="addItem()">Add</button>
</div>
<p>Write in the input field to add items.</p>
</body>
You need to add track by $index like following. AngularJS does not allow duplicates in a ng-repeat directive. You will get error if you try to do that.
If you want to allow duplicate, you need to change your code like following.
<li ng-repeat="x in products track by $index">{{x}}</li>
Example
var app = angular.module("myShoppingList", []);
app.controller("myCtrl", function($scope) {
$scope.products = ["Milk", "Bread", "Cheese"];
$scope.addItem = function() {
$scope.products.push($scope.addMe);
}
});
<html>
<head>
<link rel="stylesheet" href="style.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.5/angular.js"></script>
</head>
<body>
<div ng-app="myShoppingList" ng-controller="myCtrl">
<ul>
<li ng-repeat="x in products track by $index">{{x}}</li>
</ul>
<input ng-model="addMe">
<button ng-click="addItem()">Add</button>
</div>
<p>Write in the input field to add items.</p>
</body>
</html>
I'm having trouble trying to figure out how to fix a bug that happens when I try to push the same string as added previously to the array. It gets stuck and will not allow the app to post another string.
How do I make sure that your repeat doesn't get stuck when there two of the same values in the array?
Bug Example Screenshot
--> Bug happens when I try to push "1"into the array again after a "1" is already posted.
HTML Code
<body>
<div data-ng-controller="appController" class="container">
<div class="row">
<form>
<label for = "status"> Status: </label>
<input data-ng-model = "input_data" type="text" id="status"/>
<button data-ng-click="add_data()"> OK </button>
<ul class = "list-group">
<li class="list-group-item" data-ng-repeat="x in array_data">
{{x}}
<button data-ng-click = "remove_data($index)">DEL</button>
</li>
</ul>
</form>
</div>
</div>
<script src="framework/js/jquery.min.js"></script>
<!-- All Bootstrap plug-ins file -->
<script src="framework/js/bootstrap.min.js"></script>
<!-- Basic AngularJS -->
<script src="framework/js/angular.min.js"></script>
<!-- Your Controller -->
<script src="framework/js/appstatpost.js"></script>
</body>
AngularJS code
var app = angular.module("myApp", []);
app.controller("appController", function ($scope) {
$scope.array_data = [];
$scope.add_data = function () {
$scope.array_data.push($scope.input_data);
};
$scope.remove_data = function (index) {
$scope.array_data.splice(index, 1);
};
});
You could use track by $index, example:
<li class="list-group-item" data-ng-repeat="x in array_data track by $index">
AngularJS tries by default to find a key in your array to index by. Normally this works well, but if you have duplicates then you have to tell AngularJS to make a new index, in this case, $index.
I need one help. I need to create extra input element using ng-repeat in angular.js. I did something but its not working. I explaining my code below.
<div>
<ul>
<li ng-repeat="r in arr">
<input type="text" ng-model="r.uname">
</li>
</ul>
</div>
<button type="button" id="btn" ng-click="create();">Add</button>
Here I need when user will click on add button the new input field will create just below the first one. My scripting side code is given below.
<script type="text/javascript">
function ContactController($scope){
$scope.arr=[{uname:null}];
$scope.create=function(){
console.log('hii');
$scope.arr.push({
uname:null
});
console.log('hi',$scope.arr);
}
}
</script>
But here i am unable to generate the new input type element. Please help me.
I don't see an error in your code. it works: http://jsfiddle.net/Lvc0u55v/9536/
$scope.arr=[{uname: null}];
$scope.create = function(){
console.log('hii');
$scope.arr.push({
uname: null
});
console.log('hi',$scope.arr);
}
Define your array like this..
$scope.arr=[{}];
$scope.create=function(){
$scope.arr.push({});
console.log('hi',$scope.arr);
}
everything else looks fine..
Please refer to this.
Use track by in order to achieve the thing you're aiming for:
<li ng-repeat="r in arr track by $index">
the first thing u are pushing the same element in the array so you want to track the in the ng-repeat
<div ng-repeat="r in arr track by $index">
<input type="text" ng-model="r.uname"> </div>
still it is not creating then try the console is coming and it is not creating
use $scope.$apply() to manually run the digest cycle
Which version of angular are you running. The code which you mentioned would not work in angular 1.3 and above. It works in 1.2 though. See this with 1.2
https://plnkr.co/edit/52ygFNbSFZQr3SdCvlDc?p=preview
<body ng-controller="ContactController">
<p>Hello {{name}}!</p>
<div>
<ul>
<li ng-repeat="r in arr">
<input type="text" ng-model="r.uname">
</li>
</ul>
</div>
<button type="button" id="btn" ng-click="create();">Add</button>
<script type="text/javascript">
function ContactController($scope){
$scope.arr=[{uname:null}];
$scope.create=function(){
console.log('hii');
$scope.arr.push({
uname:null
});
console.log('hi',$scope.arr);
}
}
</script>
For 1.4 and above use the following. https://plnkr.co/edit/t7STLztqoMiPKaiHr62V?p=preview
<body ng-controller="ContactController">
<p>Hello {{name}}!</p>
<div>
<ul>
<li ng-repeat="r in arr">
<input type="text" ng-model="r.uname">
</li>
</ul>
</div>
Add
app.controller('ContactController', function($scope) {
$scope.name = 'World';
$scope.arr=[{uname:null}];
$scope.create=function(){
console.log('hii');
$scope.arr.push({
uname:null
});
console.log('hi',$scope.arr);
}
});
I've got a page in my website in which I want to show a checkbox. I only want to show the checkbox if the model is initially false. So I wrote this (this was my initial code, but it was a simplified version of what I have myself. I updated the code in the snippet at the end of this question to show the problem):
<div ng-if="!the_field">
<input ng-model="the_field" type="checkbox">
</div>
The problem is that if I click the checkbox, it disappears. That of course makes sense, but I have no idea how to solve this.
So what I basically want is to show the checkbox if the model was false upon rendering the HTML. But after that I want to somehow break the databinding so that the checkbox remains on the page even if the model changes to true.
Does anybody know how I can achieve this? All tips are welcome!
[EDIT]
I would prefer doing this from within the template, so that I don't get a double list of these fields (because I've got about 50 of them). Any ideas?
[EDIT 2]
Turns out that it did work with the example above, which was a simplified version of my own code. In my own code however, I'm not using simple a field, but an item in a dict. I updated the code above and made a snippet below to show the problem:
var MainController = function($scope){
$scope.the_field = {};
$scope.the_field.item = false;
};
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="" ng-controller="MainController">
parent: {{the_field.item}}
<div ng-if="!the_field.item">
child: {{the_field.item}}<br>
<input ng-model="the_field.item" type="checkbox">
</div>
</div>
You can clone the source object. Like this:
angular.module('app', []).
controller('ctrl', function($scope) {
$scope.the_field = false;
$scope.the_field_clone = angular.copy($scope.the_field);
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.0/angular.min.js"></script>
<div ng-app="app" ng-controller="ctrl">
{{the_field}}
<div ng-if="!the_field_clone">
<input ng-model="$parent.the_field" type="checkbox">
</div>
</div>
http://jsbin.com/ditoka/edit?html,js
Update - option 2 - Directive
angular.module('app', []).
controller('ctrl', function($scope) {
$scope.the_field = false;
}).
directive('customIf', function() {
return {
scope: {
customIf: '='
},
link: function(scope, element, attrs) {
if (!scope.customIf) {
element.remove();
}
}
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.0/angular.min.js"></script>
<div ng-app="app" ng-controller="ctrl">
{{the_field}}
<div custom-if="!the_field">
<input ng-model="the_field" type="checkbox">
</div>
</div>
It works with the code of your question, try it out ;)
(see What are Scopes?)
var MainController = function($scope){
$scope.the_field = false;
};
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="" ng-controller="MainController">
parent: {{the_field}}
<div ng-if="!the_field">
child: {{the_field}}<br>
<input ng-model="the_field" type="checkbox">
</div>
</div>
The answer to your updated question:
You can use another property in your model, edited when the first click occurs...
var MainController = function($scope){
$scope.model = {init: true, the_field: false};
};
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="" ng-controller="MainController">
parent: {{model.the_field}}
<div ng-if="!model.the_field || !model.init">
<input ng-model="model.the_field" type="checkbox" ng-click="model.init=false;">
</div>
</div>
I have something similar to this:
<div ng-controller="ControllerA">
<input type="text" id="search_form" value="Search" ng-model="searchModel" />
</div>
<div ng-controller="ControllerB">
<ul>
<li ng-repeat="item in items | filter:searchModel">{{item}}</li>
</ul>
</div>
But when I search in the input bar, it does not impact my list. How can I make my model from one controller impact the content of another?
Thanks.
Edit
ControllerA and ControllerB are entirely isolated of each other and I would like to keep it that way. If I need to share the model with the other controller, how would I use $rootScope to do that?
You can use a service to share data between controllers.
Use the factory feature which angular has to define the service.
Here is an example which i found here with and easy google search.
<!doctype html>
<html ng-app="project">
<head>
<title>Angular: Service example</title>
<script src="http://code.angularjs.org/angular-1.0.1.js"></script>
<script>
var projectModule = angular.module('project',[]);
projectModule.factory('theService', function() {
return {
thing : {
x : 100
}
};
});
function FirstCtrl($scope, theService) {
$scope.thing = theService.thing;
$scope.name = "First Controller";
}
function SecondCtrl($scope, theService) {
$scope.someThing = theService.thing;
$scope.name = "Second Controller!";
}
</script>
</head>
<body>
<div ng-controller="FirstCtrl">
<h2>{{name}}</h2>
<input ng-model="thing.x"/>
</div>
<div ng-controller="SecondCtrl">
<h2>{{name}}</h2>
<input ng-model="someThing.x"/>
</div>
</body>
</html>
if you have a model that needs to be shared you should use a service that way both controller can access the data and be aware of any changes