How to deal with dynamically added inputs with ngModel attribute on them - angularjs

I have an app that creates input elements dynamically when a user clicks a button.
It looks something like this:
[ input ] [+]
That input has an ng-model and I can use $compile when appending new inputs to have Angular treat them as if they were in the DOM at bootstrap time.
I can increment the ng-model value to say "item1", "item2" etc, but I don't like that.
I would like to know if there's a away to have an array that holds all values from all inputs.
Thanks.

You could try this:
HTML
<div ng-controller="myCtrl">
<button ng-click="addInputField()">add</button>
<ul>
<li ng-repeat="item in items">
<input type="text" id="item{{input.id}}" ng-model="item[$index]"/>
</li>
</ul>
data:
<div ng-repeat="item in items">
{{item}}
</div>
</div>
CONTROLLER
angular.module('app',[])
.controller('myCtrl',function($scope){
$scope.items = [];
$scope.addInputField = function(){
$scope.items.push({});
}
});
Here is the JSFiddle demo
'Items' is the data that binding to the input field list. You can maintain the view by updating the items array within scope and bind the elements of array to each input field view.
Hope this is helpful.

Related

How to display map object content in AngularJS ng-repeat

I have a map object in my angular controller like this,
var map = new Map();
map.set(1,'a');
map.set(2,'b');
map.set(3,'c');
map.set(4,'d');
$scope.map = map;
How do I display its content in my html file using ng-repeat?
I tried the following, they didn't work
<div ng-repeat ="m in map">
{{m}}
</div>
<div ng-repeat ="(key, value) in map">
{{key}}
{{value}}
</div>
You don't as ng-repeat iterates over an array of objects. But you can use something like Agular Filter GroupBy for that. Or change structure of your array to [{key: 'key', value: 'value'},..] and change ng-repeat to
<div ng-repeat ="item in map">
{{item.key}}
{{item.value}}
</div>

Adding items to an array seems to break ngRepeat

I have an array that I display using ngRepeat and I have a form at the bottom that enables adding to the said array. This is used to work in previous version of angular; The way items are tracked in ngRepeat have changed in newer versions of angular, so I'm not sure yet if this is a big, but when I push an item to an array, all the items seem to be binded to the same model.
This is how I add an item:
var vm = this;
this.items = [];
this.addItem = function(item) {
vm.items.push(item);
}
and I loop over them like this:
<ul>
<li ng-repeat="item in main.items track by $index">{{item.id}} - {{item.value}}</li>
</ul>
<hr>
<input ng-model="main.newItem.id" type="text" placeholder="id">
<input ng-model="main.newItem.value" type="text" placeholder="value">
<button ng-click="main.addItem(main.newItem)">Add Item</button>
Here is a plnkr demonstrating the issue.
Answer by user Blackhole
Need to make a copy of the item before adding it to the array
vm.items.push(angular.copy(item));

ng-click showing all the hidden text field on ng-repeat rather than one in Angular

I started to work with Angular, it's pretty good to implement, I stuck with a single issue at ng-click
I am getting data dynamically and showing with ng-repeat, and I want to update the data at pencil click and for it I am using input text element, but when I click on pencil It's opening all the text fields
Here is my HTML code
<
div ng-repeat="item in scroller.items track by $index">
<div class="secHead text-center">
<button class="common btnDarkGrey" data-ng-hide="hideCatButton">{{item.category_name}}</button>
<input type="text" id="focus-{{$index}}" class="common btnDarkGrey editDashboardCategory" name="editCategory" value="" data-ng-model="item.category_name" data-ng-show="hideField">
<span data-ng-click="updateCategory(item.category_id,item.category_name,$index)" class="chkOneDone" data-ng-show="hideOkButton">Done</span>
<div class="pull-right">
</div>
</div>
</div>
And here I Angular code
$scope.updateCategory=function(category_id,updated_cat_name, $index){
Category.updateCat($rootScope,$scope,$index,$http,$timeout,updated_cat_name,old_cat_name,category_id);
};
$scope.updatePen=function($index){
old_cat_name=$scope.scroller.items[$index].category_name
$scope.hideField=true;
$rootScope.hideOkButton=true;
$rootScope.hideCatButton=true;
};
I created a Category service to perform task like update
I didn't get any proper solution yet.
Can anybody help me?
Thank You.
If you only want to hide/show one of the elements in the list you need to specify that in some fashion. Right now you have a three rootScope booleans:
$scope.hideField=true;
$rootScope.hideOkButton=true;
$rootScope.hideCatButton=true;
being set for the entire list, and you need to set a show properties on each individual in the list.
In your controller function you can do something like this before you expect a click:
//normal for loop so that you have the index
for(var i=0; i < $scope.scroller.items.length; i++){
$scope.scroller.items[i].show = false;
}
Then you can do something like this to actually show the fields:
HTML:
div ng-repeat="item in scroller.items track by $index">
<div class="secHead text-center">
<button class="common btnDarkGrey" ng-hide="!item.show">
{{item.category_name}}</button>
<input type="text" id="focus-{{$index}}" class="common btnDarkGrey editDashboardCategory" name="editCategory" value="" ng-model="item.category_name" ng-hide="!item.show">
<span data-ng-click="updateCategory(item.category_id,item.category_name,$index)" class="chkOneDone" ng-show="item.show">Done</span>
<div class="pull-right">
</div>
</div>
</div>
Controller:
//controller declaration --
$scope.updatePen = function(index){
$scope.scroller.items[index].show = true;
};
It's my understanding that you need all three properties to show once a click happens, so I condensed all the show properties into one single show property.
Your view only sees that hideField is true and performs that action for all of the items in your array. I hope this helps!

Submit and disable all buttons in an ng-repeat without adding a new property on the scope

I have a list of items where each item is clickable and should trigger the submit(id) function. I would like to disable all items (buttons) when one of them is clicked.
<ul>
<li ng-repeat="item in items">
<button ng-click="submit(item.id)">Submit</button>
</li>
</ul>
I could define $scope.submitted variable in a controller and then set ng-disabled="submitted" in my view. I could also wrap it into a <form> and use frm.$submitted. Well... I would like to define everything inside view.
I search for an elegant solution where a don't have to define a $scope variable to achieve this. What do you propose?
If you do not want to define a property in the controller, and assuming that submit function never fails to submit. You could utilize the items array itself, by adding a property when click happens and after submit function is run.
<ul>
<li ng-repeat="item in items">
<button ng-click="submit(item.id); items.submitted=true"
ng-disabled="items.submitted">Submit</button>
</li>
</ul>
With this you are adding a property in the array items (so that it is available across child scopes of ng-repeat as well as items is set on its parent scope) so essentially you are not defining a new scope variable for this.
angular.module('app',[]).controller('ctrl', function($scope){
$scope.items = [{id:1},{id:2},{id:3},{id:4}]
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app" ng-controller="ctrl">
<ul>
<li ng-repeat="item in items">
<button ng-click="submit(item.id); items.submitted=true"
ng-disabled="items.submitted">Submit</button>
</li>
</ul>
</div>

ng-repeater issue Duplicates in a repeater is not allowed

I'm trying to create a form like below, this using ng-repeat directive in angular and it whenever I created a new row complains
"Duplicates in a repeater are not allowed.".
While I understand the solution for this is by putting "track by $index", however it causes another issue, which clicking delete on one row deletes the value of other field. So I suspect that track by index is OK for static text but not input form. So how to use ng-repeat correctly for my case? See my JSFiddle for demo.
My current code :
HTML
<div class="row-fluid spacer10">
<a ng-click="addAKA()" class="btn btn-primary spacer5 left30"><i class="icon-plus icon-white"></i> Add New Alias</a>
</div>
<div class="row-fluid spacer10"></div>
<div class="row-fluid spacer5" ng-repeat="item in aliasList track by $index">
<input type="text" class="span6 left30" ng-model="item">
<button class="btn btn-danger" ng-click="deleteAKA($index)">delete</button>
<BR/>
</div>
Javascript
$scope.addAKA = function ()
{
if($scope.aliasList == null)
{
$scope.aliasList = [];
}
$scope.aliasList.push("");
$scope.aliasjson = JSON.stringify($scope.aliasList);
}
$scope.deleteAKA = function (idx)
{
var aka_to_delete = $scope.aliasList[idx];
$scope.aliasList.splice(idx, 1);
$scope.aliasjson = JSON.stringify($scope.aliasList);
}
Just change the way you iterate. Instead of this:
<div ng-repeat="item in aliasList track by $index">
do this:
<div ng-repeat="item in aliasList">
$index will be still available inside the element, use like this:
<button ng-click='deleteItem($index)'>Delete</button>
See this JSFiddle for a correct solution
There are multiple problems with your approach.
Since you are directly binding a string to ng-model and ng-repeat creates a child scope, any change to the value would not reflect back. Change you scope model to something like
$scope.list = [{text:"one"},{text:"two"}];
and bind to i.text instead of binding to i as you did earlier.
The deleteItem method was called using item instead of index. See my fiddle here
http://jsfiddle.net/JS6aJ/1/

Resources