I want to be able to populate a text input field inside an ng-repeat loop with the value of another field inside that same loops index when I click a button.
JSFiddle of what I have so far: http://jsfiddle.net/3FKMx/
When the Copy Names button is clicked I want each text box to be populated with the same value that's in the array. Currently it populates them all with the value of the last item in the array.
Controller:
var app = angular.module('myApp', []);
function someController($scope) {
$scope.names = ["name1","name2","name3"];
$scope.copyNames = function() {
angular.forEach($scope.names,
function (value){
$scope.newName = value;
}
);
};
}
Template:
<div ng-controller="someController">
<button class="btn btn-primary" ng-click="copyNames()">Copy Names</button>
<table>
<tr ng-repeat="name in names">
<td>{{name}}</td>
// I want to populate this input with {{ name }} when I click the button above.
<td><input type="text" ng-model="newName"/></td>
</tr>
</table>
</div>
Solution 1
With an updated data structure it's a bit nicer for looping through.
Solution 2
Create a new array to store the values. Set them by key and look them up by key in your curly braces.
html
<div ng-controller="someController">
<button class="btn btn-primary" ng-click="copyNames()">Copy Names</button>
<table>
<tr ng-repeat="name in names">
<td>{{name}}</td>
<td><input type="text" ng-model="models[name]"/></td>
</tr>
</table>
</div>
JavaScript
var app = angular.module('myApp', []);
function someController($scope) {
$scope.names = ["name1","name2","name3"];
$scope.models = {};
$scope.copyNames = function() {
angular.forEach($scope.names,
function (value, key) {
$scope.models[value] = value;
}
);
};
}
DEMO (updated your fiddle) is what you are looking for?
Tried using an object to hold the label and model:
$scope.names = [{label: "name1", model: ''},
{label: "name2", model: ''},
{label: "name3", model: ''}];
//Also using jQuery.each to break from the loop
//once we know which value to copy
$scope.copyNames = function() {
$.each($scope.names,
function (i, value){
if(value.model) {
angular.forEach($scope.names, function(name){
name.model = value.model;
});
//Break the loop if done copying
return false;
}
}
);
};
Note: jQuery is used as an external library which will be available in angular as is.
Related
Hi I am adding Dynamically form fields like this
<div ng-repeat="exam_student in exam_students">
<select
ng-model="exam_student.student_id"
options="students"
ng-options="student.id as student.name for student in students">
</select>
<button type="button" ng-click="removeStudent($index)">-</button>
</div>
<button type="button" ng-click="addStudent()">Add Student</button>
js
$scope.students = [{id: 1, name: 'st1'},
{id: 2, name: 'st2'}];
$scope.exam_students = [{}];
$scope.addStudent = function(){
$scope.exam_students.push({});
}
$scope.removeStudent = function(index){
$scope.exam_students.splice(index,1);
}
Each time a user clicks on Add Student button the form field added but how do i disable the previous selected option in a select element.
Thank you for your any help and suggestions
didn't fully test or optimize it, but this is something you can do.
add track by $index in ng-repeat and add ng-disabled in the select tag with
<div ng-controller='MyController'>
<div ng-repeat="exam_student in exam_students track by $index">
<select
ng-model="exam_student.student_id"
options="students"
ng-options="student.id as student.name for student in students"
ng-disabled="exam_students.length > 1 && exam_students.length > $index + 1">
</select>
<button type="button" ng-click="removeStudent($index)">-</button>
</div>
<button type="button" ng-click="addStudent()">Add Student</button>
</div>
https://jsfiddle.net/4xfzmuub/
exam_students.length > 1 is to prevent the first field from being disabled
===========================================================================
updated answer. Instead of using select with ng-options, I chose to use select with ng-repeat option. This was what I tried and not working.
ng-options="student.id as student.name disable when student.disable for student in students"
The options were able to be disabled. Unfortunately Angular won't let me set the value to ng-model since the option has been disabled. A workaround is to use select with ng-repeat option
html:
<div ng-controller='MyController'>
<div ng-repeat="exam_student in exam_students track by $index">
<select ng-model="exam_student.student_id" ng-change="hasChange()">
<option ng-repeat="student in students" value={{::student.id}} ng-disabled="student.disable">{{::student.name}}</option>
</select>
<button type="button" ng-click="removeStudent($index)">-</button>
</div>
<button type="button" ng-click="addStudent()">Add Student</button>
</div>
js:
var app = angular.module('myApp', []);
app.controller('MyController', ['$scope', MyController]);
function MyController($scope) {
// I suggest adding an empty object so that we can re-select the options
$scope.students = [{},{id: 1, name: 'st1', disable: false},
{id: 2, name: 'st2', disable: false},
{id: 3, name: 'st3', disable: false}];
$scope.exam_students = [{}];
$scope.addStudent = function(){
$scope.exam_students.push({});
}
$scope.removeStudent = function(index){
$scope.exam_students.splice(index,1);
$scope.hasChange();
}
$scope.hasChange = function() {
// using a lookup table, instead of 2 nested loops, for a better performance when the list gets large
var lookupTable = {};
// store the student_id in the lookupTable and set it to true
// worth noting since I am using option tag, student_id will be stored as string instead of number, but it is ok because key in javascript object will be converted to string
$scope.exam_students.forEach(function(exam_student) {
lookupTable[exam_student.student_id] = true;
// or lookupTable[Number(exam_student.student_id)] = true;
});
// loop through the options and if student_id is true/there, set disable accordingly
$scope.students.forEach(function(student) {
if(lookupTable[student.id]) {
student.disable = true;
}else {
student.disable = false;
}
//or student.disable = lookupTable[student.id];
});
}
}
https://jsfiddle.net/apop98jt/
I am having an array with objects like [{...}, {...}] which I am outputting with ng-repeat. Then I have a delete button with a function to delete it.
Is there a simple way to delete it in AngularJS, perhaps with $index? Or I need to specify an ID on every object as an property?
If you don't apply a filter to reorder or filter your array, you can do this:
<div ng-repeat="item in items" ng-click="delete($index)">{{item}}</div>
And the delete function:
$scope.items = [...];
$scope.delete = function (index) {
$scope.items.splice(index, 1);
}
Another way to do it without filter problems: (ONLY IE9+)
<div ng-repeat="item in items | orderBy: 'id'" ng-click="delete(item)">{{item}}</div>
And the delete function:
$scope.items = [...];
$scope.delete = function (item) {
$scope.items.splice($scope.items.indexOf(item), 1);
}
http://jsfiddle.net/oymo9g2f/2/
Here is another example, using Jade too:
template.jade:
label All Items
ul.list-group
li.list-group-item(ng-repeat="item in items | orderBy: '_id'")
strong {{item.name}}
a.trash(ng-click='deleteItem(item)')
//a.trash is a bootstrap trash icon, but you don't need to use it.
controller.js:
$scope.deleteItem = function (item) {
$scope.items.splice($scope.items.indexOf(item),1);
}
removeWith
comparison for each element in a collection to the given properties object,
returning an array without all elements that have equivalent property values.
$scope.collection = [
{ id: 1, name: 'foo' },
{ id: 1, name: 'bar' },
{ id: 2, name: 'baz' }
]
<tr ng-repeat="obj in collection | removeWith:{ id: 1 }">
{{ obj.name }}
</tr>
<tr ng-repeat="obj in collection | removeWith:{ id: 1, name: 'foo' }">
{{ obj.name }}
</tr>
First try to do it this way, but the listing was not actualized at runtime.
$scope.delete = function (index) {
delete $scope.items[index];
}
Then with the answer given above by Facundo Pedrazzini did work properly for me.
$scope.delete = function (index) {
$scope.items.splice(index, 1);
}
Version: AngularJS v1.6.4
In blade.php
<table style="width:100%;">
<tr ng-repeat="name in planFormData.names track by $index">
<td>
<div class="form-group">
<label>Plan Name<span style="color:red;">*</span> </label>
<input type="text" class="form-control" ng-model="planFormData.names[$index].plan_name" name="plan_name" id="status-name" placeholder="Plan Name" autocomplete="off" required>
</div>
</td>
<td>
<i class="icon-plus" ng-click="addRow($index)" ng-show="$last"></i>
<i class="icon-trash" ng-click="deleteRow($event,name)" ng-show="$index != 0"></i>
</td>
</tr>
</table>
In controller.js
$scope.deleteRow = function($event, name) {
var index = $scope.planFormData.names.indexOf(name);
$scope.planFormData.names.splice(index, 1);
};
In Angular 6, I did similar for Multi Dimensional Array. It's working
RemoveThisTimeSlot(i: number, j: number) {
this.service.formData.ConsultationModelInfo.ConsultationWeekList[i].TimeBlockList.splice(j, 1);
}
I am using Checklist model directive with my App. I have issue, if -
I click select all button though it write up the array but its not
selecting checkbox. Same issue with Uncheck All though it empty the
model but it doesn't uncheck checkboxes.
If I select 2 or 3 randomly checkbox and click Select All Button it doesn't select All check-boxes.
Though its writing values to pushArray. But issues are checking and unchecking checkboxes.
$scope.items = [{id:1, name:"abc"},{id:2, name:"def"},{id:3, name:"ghi"}];
$scope.pushArray = [];
<table>
<tr ng-repeat="e in items">
<td class="text-right">
{{e.id}}
<input type="checkbox" checklist-change="imChanged()" checklist-model="pushArray" checklist-value="e.id" >
</td>
</tr>
</table>
I think you are pushing the complete list of object which is wrong. You just need to map the list and pass the id to the $scope
Edit: Works fine when you use $scope.pushArray as an object instead of array.
Working Plnkr
HTML
<body ng-controller="selection">
<table>
<tr ng-repeat="e in items">
<td>
<input type="checkbox" checklist-model="pushArray.ids" checklist-value="e.id"> {{e.name}}
</td>
</tr>
</table>
{{pushArray.ids | json}}
<br />
<button ng-click="select_all();">Select All</button>
<button ng-click="unselect_all();">Unselect All</button>
</body>
JS
var app = angular.module('app', ["checklist-model"]);
app.controller('selection', ['$scope', function($scope) {
$scope.items = [{
id: 1,
name: "abc"
}, {
id: 2,
name: "def"
}, {
id: 3,
name: "ghi"
}];
$scope.pushArray = { ids: []}; // Works fine when using it as an object
//$scope.pushArray = [];
$scope.select_all = function() {
$scope.pushArray.ids = $scope.items.map(function(item) { return item.id; });
};
$scope.unselect_all = function() {
$scope.pushArray.ids = [];
};
}]);
Hope it works for you!
I updated the examples on checklist-model and fix this issue. Check them out http://vitalets.github.io/checklist-model/
I wanna update an object within an objects array. Is there another possibility than iterating over all items and update the one which is matching? Current code looks like the following:
angular.module('app').controller('MyController', function($scope) {
$scope.object = {
name: 'test',
objects: [
{id: 1, name: 'test1'},
{id: 2, name: 'test2'}
]
};
$scope.update = function(id, data) {
var objects = $scope.object.objects;
for (var i = 0; i < objects.length; i++) {
if (objects[i].id === id) {
objects[i] = data;
break;
}
}
}
});
There are several ways to do that. Your situation is not very clear.
-> You can pass index instead of id. Then, your update function will be like:
$scope.update = function(index, data) {
$scope.object.objects[index] = data;
};
-> You can use ng-repeat on your view and bind object properties to input elements.
<div ng-repeat="item in object.objects">
ID: <input ng-model="item.id" /> <br/>
Name: <input ng-model="item.name" /> <br/>
</div>
Filters that help in finding the element from the array, can also be used to update the element in the array directly.
In the code below [0] --> is the object accessed directly.
Plunker Demo
$filter('filter')($scope.model, {firstName: selected})[0]
Pass the item to your update method. Take a look at sample bellow.
function MyCtrl($scope) {
$scope.items =
[
{name: 'obj1', info: {text: 'some extra info for obj1', show: true}},
{name: 'obj2', info: {text: 'some extra info for obj2', show: false}},
];
$scope.updateName = function(item, newName){
item.name = newName;
}
}
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body ng-app>
<table ng-controller="MyCtrl" class="table table-hover table-striped">
<tr ng-repeat="x in items">
<td> {{ x.name }}</td>
<td>
Update
<div ng-show="showUpdate" ><input type="text" ng-model="someNewName"> <input type="button" value="update" ng-click="updateName(x, someNewName); showUpdate = false;"></div>
</td>
</tr>
</table>
</body>
Going off your plunker, I would do this:
Change
Edit
to be
Edit
Then use the array index within your $scope.selectSubObject method to directly access your desired element. Something like this:
$scope.selectSubObject = function(idx) {
$scope.selectedSubObject = angular.copy(
$scope.selectedMainObject.subObjects[idx]
);
};
If however, you only have the id to go off of, then you can use the angular filterService to filter on the id that you want. But this will still do a loop and iterate over the array in the background.
See angularjs documentation for ngrepeat to see the variables that it exposes.
Using angular.js, I have a dynamic list of form fields I want to display to the user for editing (and later submission):
var app = angular.module('app', []);
app.controller('Ctrl', function($scope) {
$scope.fields = {
foo: "foo",
bar: "bar",
baz: "baz"
};
});
And the HTML:
<div ng-app="app" ng-controller="Ctrl">
<table>
<th>key</th>
<th>value</th>
<th>fields[key]</th>
<tr ng-repeat="(key,value) in fields">
<td>{{key}}:</td>
<td><input type="text" ng-model="value"/></td>
<td><input type="text" ng-model="fields[key]"/></td>
</tr>
</table>
</div>
See this fiddle. For a reason I don't understand, the text input boxes aren't editable. I've tried two different ways as seen above: value and fields[key]. value isn't editable at all, and fields[key] will allow one keystroke and then it blurs. What am I doing wrong? Thank you.
SET answered why it's happening, but a work-around to achieve the desired behavior would be to maintain a separate array of your keys, and run ng-repeat off those keys. I added some text fields for testing to add more properties to $scope.fields
You could use $watch to dynamically set the keys when the property count changes, if your requirements were that the field count may change.
http://jsfiddle.net/aERwc/10/
markup
<div ng-app="app" ng-controller="Ctrl">
<table>
<th>key</th>
<th>value</th>
<tr ng-repeat="key in fieldKeys">
<td>{{key}}:</td>
<td><input type="text" ng-model="fields[key]"/></td>
</tr>
</table>
<div><h6>Add a field</h6>
key: <input type="text" ng-model="keyToAdd" /><br />
value: <input type="text" ng-model="valueToAdd" />
<button ng-click="addField()">Add Field</button>
</div>
</div>
controller
var app = angular.module('app', []);
app.controller('Ctrl', function($scope) {
$scope.fields = {
foo: "foo",
bar: "bar",
baz: "baz"
};
$scope.fieldKeys = [];
$scope.setFieldKeys = function() {
var keys = [];
for (key in $scope.fields) {
keys.push(key);
}
$scope.fieldKeys = keys;
}
$scope.addField = function() {
$scope.fields[$scope.keyToAdd] = $scope.valueToAdd;
$scope.setFieldKeys();
$scope.keyToAdd = '';
$scope.valueToAdd = '';
}
$scope.setFieldKeys();
});
It is editable but after each key press your text field losing focus so that you have to click on it again to put another char.
And that happens because whole you template being re-rendered after each change in any of models. And after template re-rendered, currently there is no way to know which input should be focused. So you should create that way and you may want to write directive to hold focus on selected input.
You need to use an array of objects. Hopefully you can rework your model:
$scope.fields = [
{label: "foo", value: "foov"},
{label: "bar", value: "barv"},
{label: "baz", value: "bazv"}
];
<tr ng-repeat="field in fields">
<td>{{field.label}}:</td>
<td><input type="text" ng-model="field.value">
Fiddle.