I have an ng-repeat with a comment input inside the loop. With a ng-model="comss.comment", however when I start to type on the first input, I can see the typing on the 2nd and all of the other inputs. How can I stop this? I've tried adding a name with a unique ID however that did not work.
Here is my code:
<li class="item" style="margin-top:20px;" ng-repeat="schedule in discoverloaded | filter:scheduleSearch | limitTo:numberOfItemsToDisplay">
<input type="text" ng-model="comss.comment" required='required' placeholder="Write a comment..">
</li>
Since you're in a loop, accessing comss.comment for each loop is going to be the same model, you need to modify your template and the model slightly:
<li class="item" style="margin-top:20px;"
ng-repeat="schedule in discoverloaded | filter:scheduleSearch | limitTo:numberOfItemsToDisplay track by $index">
<input type="text" ng-model="comss[$index].comment"
required='required' placeholder="Write a comment..">
</li>
In the controller it would be a larger object, so for a loop of two items in discoverloaded, you would have this in comss:
comss = {
0: {
comment: ''
},
1: {
comment: ''
}
};
In the template you can't access it via comss.0.comment, which is why you use comss[$index].comment as you're inside the loop when you assign the model.
Related
How do I access value of ItemName in HTML. It says undefined when I try {{invoiceForm.controls[i].items.controls.itemName.value | json}} in below code.
<form [formGroup]="invoiceForm">
<div formArrayName="items" *ngFor="let item of items.controls; let i=index;">
<div [formGroupName]="i">
<input type="text" formControlName="itemName">
<input type="number" formControlName="itemQty">
<input type="number" formControlName="itemPrice">
</div>
Item name: {{invoiceForm.controls[i].items.controls.itemName.value | json}}
</div>
</form>
You were almost there...
instead of:
{{invoiceForm.controls[i].items.controls.itemName.value | json}}
You should write:
{{invoiceForm.controls['items'].controls[i].controls.itemName.value | json}}
StackBlitz example
In order to tell the exact path to go, you could have just print the form value with console.log(this.invoiceForm) on ngOnInit and then you could have seen that the 'item' is a direct key of 'controls', your only mistake was to refer invoiceForm.controls[0] which is wrong.
Here is a little extra for achieving the same outcome form ts file (hard coded to the first item):
console.log(this.invoiceForm);
const itemControls = <FormArray>this.invoiceForm.controls['items'];
const itemFormGroup = <FormGroup>itemControls.controls[0];
console.log(itemFormGroup.controls["itemName"].value);
I want to be able to add/remove items in an order and have them aggregate into an array to be sent to the backend. The data will look like:
CustomerName: Billy
Orders: [Pizza, Burger, Sushi]
Can't find any SO answers or documentation that gets into iterated input binding. Anyone attempted this? Template code:
<div>
<input
type="text"
name="name"
title="name"
placeholder="Customer Name"
[(ngModel)]="customerName"/>
</div>
<div *ngFor="let item of itemsInNewOrder; let i = index">
<input
type="text"
name="order"
title="order"
[(ngModel)]="itemsInNewOrder[index]"/>
</div>
inside the Add New button's click function:
...firebaseStuff... .push({name: name, order: this.itemsInNewOrder})
unfortunately, this doesn't work. Thanks in advance! :)
Edit 1: There are 2 buttons that trigger (respectively):
incrementItemsInNewOrder() {
this.itemsInNewOrder.push("")
}
decrementItemsInNewOrder() {
this.itemsInNewOrder.pop()
}
I can see one problem. You should use the variable i that you have declared in template.
<div *ngFor="let item of itemsInNewOrder; let i = index">
<input
type="text"
name="order"
title="order"
[(ngModel)]="itemsInNewOrder[i]"/> <------ HERE
</div>
EDIT
angular seems to be doing change detection when typing into the inputs and renders them again, when that happens you lose the focus.
but if you wrap the values into objects and suddenly it works.
Component:
itemsInNewOrder = [{value: 'Soda'}, {value: 'Burger'}, {value: 'Fries'}];
template:
<div *ngFor="let item of itemsInNewOrder; let i = index">
<input
type="text"
name="order"
title="order"
[(ngModel)]="itemsInNewOrder[i].value"/>
</div>
I want to use ng-repeat object in ng-model value as sub string.. can i use this?? My scenario is:
<form id="booking_form" name="booking_form" ng-app="myApp" ng-submit="tasksubmit()">
<ul class="items-list">
<li ng-repeat="task in taskslist | filter:query | orderBy:orderProp" class="items-list-item">
<div class="items-list-item-image">
<p>
<input type="checkbox" ng-model="tasksubmit{{task.id}}" />
</p>
</div>
<div class="items-list-item-detail">
<p>
<strong>{{task.title}}</strong>
</p>
</div>
</li>
</ul>
</form>
in < input type = checkbox > i want to generate dynamic ng-model with prefix of tasksubmit (this is initialized in controller as $scope.tasksubmit = {} ). Any body please help me out in this problem.....
If I understand correctly you want all task.id as property inside your tasksubmit object as you have initialized it as object in your controller so you can do as below:
<input type="checkbox" ng-model="tasksubmit[task.id]" />
Just add model with ngRepeat's instance property
Like this
<li ng-repeat="task in taskslist | filter:query | orderBy:orderProp" class="items-list-item">
<input type="checkbox" ng-model="task.isChecked" />
</li>
You'll find value of isChecked from $scope.taskslist
JSFIDDLE
First off I'd like to say that I'm just starting with AngularJS, so please excuse me if this is a stupid question.
I have a controller that performs an AJAX request and it returns a JSON object. This JSON is then saved as $scope.person. It look's like this:
function PersonController($scope, $http) {
$http({
method: 'GET',
url: constants.adminUrl + '/getJSON.php?data=person'
}).success(function(data, status, headers, config) {
$scope.person = data;
}).error(function(data, status, headers, config) {
throw new Error('I\'m truly sorry, but I couldn\'t fetch your data');
});
}
The file getJSON.php successfully returns what I expect, a JSON object which looks like this:
[{
"id": 1,
"firstName": "Silvestre",
"lastName": "Herrera",
"headline": "DiseƱador y front-end engineer",
"location": "Argentina",
"summary": "Summary summary summary"
}]
And then, in my HTML I have the following:
<ol ng-controller="PersonController">
<li ng-repeat="person in person | filter: {id:1}">
<input data-autoGrow name="firstName" type="text" value="{{ person.firstName }}" placeholder="<?= __("What's your first name?"); ?>"><input data-autoGrow name="lastName" type="text" value="{{ person.lastName }}" placeholder="<?= __("And your last name?"); ?>">
</li>
<li ng-repeat="person in person | filter: {id:1}"><input type="text" value="{{ person.headline }}" placeholder="<?= __("Headline"); ?>"></li>
<li ng-repeat="person in person | filter: {id:1}"><input type="text" value="{{ person.location }}" placeholder="<?= __("Where do you live?"); ?>"></li>
<li ng-repeat="person in person | filter: {id:1}"><textarea placeholder="<?= __("Write something about you..."); ?>">{{ person.summary }}</textarea></li>
</ol>
All the PHP function __() does is translate the given string. Anyway, as you can see I'm using the ng-repeat directive which I'd like to avoid as there's only one person and there will always be only one.
What I tried was using ng-model="person" in the <ul> element instead of ng-repeat="person in person" in every <li> and then try printing {{ person.firstName }} but nothing gets printed. But if I print {{ person }} I do get the whole object.
Well, I guess that pretty much sums up my problem. Thanks in advance for any input!
Can't you do like this?:
$scope.person = data[0];
You don't use the ng-model directive when you're setting the content of an HTML tag. ng-model is the Angular way to handle the value attribute in form fields. For your purposes, you should be able to just write:
<ol ng-controller="PersonController">
<li>
<input data-autogrow name='firstName' ng-model='person[0].firstName'/>
<input data-autogrow name='lastName' ng-model='person[0].lastName'/>
</li>
<li><input ng-model='person[0].headline'/></li>
<li><input ng-model='person[0].location'/></li>
<li><textarea ng-model='person[0].summary'/></li>
</ol>
Note, the textarea tag is not actually vanilla HTML, it's an AngularJS directive implementing the same functionality, so it doesn't work in quite the same way and you can still bind the ng-model attribute instead of plugging it into the content as you would in vanilla HTML.
You can not use same variable name 'person' for array and items in array. Your code should be
$scope.people = data;
Then in html
<li ng-repeat="person in people | filter: {id:1}">
Here is my view for a list.
back...
<ul>
<input type="text" ng-model="search">
<li ng-repeat="item in items | filter:search | orderBy:'date'">
{{ item.ID }} - {{ item.heading }} - {{ item.date | date:"dd.MM.yy" }}
<button ng-click="deleteItem(item.ID)">del</button>
</li>
<form>
<input type="text" ng-model="itemName">
<input type="date" min="{{ date }}" max="{{ maxDate }}" value="{{ date }}" ng-model="itemDate">
<button ng-click="addItem()">add</button>
</form>
</ul>
On click my contoller adds a new item to the view, which works fine. Now i want to animate only the new item with css3. Therefore the new item needs a class. How can i achieve this with angular?
This should assign class the-class to the last element of the list dynamically:
<li ng-class="{'the-class': $last}" ng-repeat="item in items | filter:search | orderBy:'date'">
{{ item.ID }} - {{ item.heading }} - {{ item.date | date:"dd.MM.yy" }}
<button ng-click="deleteItem(item.ID)">del</button>
</li>
If you're using Angular 1.1.5, you can use ngAnimate enter event instead which is precisely designed for this kind of situation.
Have a look at http://www.nganimate.org/ and http://code.angularjs.org/1.1.5/docs/api/ng.directive:ngAnimate
If you use a function to add an Item, you could also set a variable to know which Id is the last inserted while adding the item to the list
First, you can see what I did here http://jsfiddle.net/DotDotDot/Eb2kR/
I just created a lastInsertedId variable, which I use to add a class in the ng-repeat :
<span ng-class='{lastinserted: item.ID==lastInsertedId}'>{{ item.ID }} - {{ item.heading }} - {{ item.date | date:"dd.MM.yy" }}</span>
I had no idea how you implemented you addItem method and what are your IDs, so I created my own method and I assumed your IDs are unique numbers, but it could work with anything (hoping you can find a unique set of data)
$scope.addItem=function(){
var dd=new Date($scope.itemDate);
$scope.items.push( {"ID":$scope.items.length+1, "heading":$scope.itemName, "date":dd.getTime()});
$scope.lastInsertedId=$scope.items.length;
}
I change the last inserted id, which will apply the selected class to the item
You could also unset the lastInsertedId value in the delItem() method
If you have a more difficult logic (here I assumed you had unique IDs) you can also use a function in the ng-class. Here, on my example it wouldn't be hard to code :
$scope.amITheOne=function(item){
return item.ID==$scope.lastInsertedId;
}
then
<span ng-class='{lastinserted: amITheOne(item)}'>
It doesn't change much with a simple logic, but you could totally have a logic based on the ID, the name and the date for example
Have fun