AngularJS: need to attach a selected collection to a model - angularjs

I'm building a CRUD and I want to some model to be linked to others. So on some update/create template I need to add some other model and save their id when submitting the form.
So I did a basic form that is served by my backend. Here is the part where I try to display the linked model:
<div ng-repeat="item in otherItems">
<select ng-model="item" name="item" >
<option value="1" ng-selected="item">
<option value="2" ng-selected="item">
<option value="3" ng-selected="item">
</select>
<a class="remove" ng-click="removeRelated(item)">remove</a>
</div>
<a ng-click="addRelated()"><i class="icon-plus"></i></a>
Note: otherItems could be empty at the beginning (when doing a create or when an item is not linked to any other related model's item).
So when one press add/remove it will trigger a controller's function:
$scope.addRelated = function (){
if (typeof $scope[otherItems]=="undefined")
$scope[otherItems] = new Array();
$scope[otherItems].push($scope[otherItems].length);
};
$scope.removeRelated = function (item){
console.debug(item);
var idx = $scope[otherItems].indexOf(item);
if (idx !== -1) {
$scope[otherItems].splice(idx, 1);
}
};
My problem is when I save I get the position of item in items (so it's always 0, 1, 2...) I won't have an array of selected ID.
I guess there is something wrong with my addRelated maybe. What am I doing wrong?
Here is a screenshot to understand the idea since I may not be very clear:

So something like this? http://plnkr.co/edit/6eqWL5
The markup..
<body ng-controller="MainCtrl">
<div ng-repeat="otherItem in otherItems">
<select ng-model="otherItem.selectedItem" ng-options="item for item in otherItem.items"></select>
<a ng-click="removeOtherItem($index)">remove</a>
</div>
<a ng-click="addOtherItem()">add</a>
<hr/>
Selected:
<ul>
<li ng-repeat="otherItem in otherItems">
otherItem[{{$index}}].selectedItem = {{otherItem.selectedItem}}
</li>
</ul>
</body>
The code
app.controller('MainCtrl', function($scope) {
$scope.otherItems = [
{
selectedItem: null,
items: [1, 2, 3]
},
{
selectedItem: null,
items: [4, 5, 6]
}
];
$scope.addOtherItem = function(){
$scope.otherItems.push({ items: [7, 8, 9]});
};
$scope.removeOtherItem = function(index) {
$scope.otherItems.splice(index, 1);
};
});
Sorry if it's off from what you're asking for... the question was a little vague, so I'm guessing at some of the functionality.

Related

angularjs dynamic add option field with disable previous selected option

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/

AngularJS ng-repeat with radio inputs

I have a list of options as an enum:
var Options = {
Option0: 0,
Option1: 1,
Option2: 2,
Option3: 3,
Option4: 4
};
And a sub-list of available options:
var availabledOptions = [
Options.Option0,
Options.Option2,
Options.Option4
];
I then try to show the list of available options as radio inputs but it doesn't work and I'm wondering why. $scope.selectedOption is not updated.
function main($scope) {
$scope.availabledOptions = availabledOptions;
$scope.selectedOption = Options.Option2;
}
</script>
<div ng-app ng-controller="main">
<ul>
<li ng-repeat="option in availabledOptions">
<input name="options" type="radio" ng-model="selectedOption" ng-value="option">option #{{option}}
</li>
</ul>
selected option: option #{{selectedOption}}
</div>
http://jsfiddle.net/1xgsqL67/
I tried ng-repeat="option in availabledOptions track by $index" and also without the name attribute, but it still doesn't work.
Thanks in advance!
Try the following:
ng-model="$parent.selectedOption"
My understanding is that ng-repeat creates it's own scope, and you have to go up one level.

angularjs set list of checkboxed checked

Well i've got 2 lists:
$scope.list = [{val: 1, name:'01'},{val: 2, name:'02'},{val: 3, name:'03'},{val: 4, name:'04'}]
$scope.selectedList = [{val: 2, name:'02'},{val: 4, name:'04'}]
and a list of comboboxes - generated by the list:
<div ng-repeat="item in list| filter: query">
<input type="checkbox" ng-change="change(isDisabled,{{item.val}})" ng-model="isDisabled" /> {{item.name}}
</div>
So how can I attach the selectedList to the checkboxes?
You need to add a ng-checked to the check box. Using a function as the expression, sending in the item that represents that check box.
ng-checked="isChecked(item)"
then the function just needs to return whether that item is in the selectedList
$scope.isChecked = function(item){
return $scope.selectedList.indexOf(item) >-1;
};

how get the list of selected items in angular.js

Here I am using angular.js to show a list of people
<div class="recipient" ng-repeat="person in people">
<img src="{{person.img}}" /> person.name
<div class="email">person.email</div>
</div>
$scope.people = [{id:1}, {id:2}, {id:3}, {id:4}];
The looks is like below
What I want to do is I can select multiple items and by click a OK button, I can get a list of selected items. so If I select id 1 and id 2, then I want to get return a list of [{id:1},{id:2}]
How could I implement it in angular.js
Well I guess that if you're looping through a collection of people using a ng-repeat, you could add the ng-click directive on each item to toggle a property of you're object, let's say selected.
Then on the click on your OK button, you can filter all the people that have the selected property set to true.
Here's the code snippet of the implementation :
<div class="recipient" ng-repeat="person in people" ng-click="selectPeople(person)">
<img src="{{person.img}}" /> person.name
<div class="email">person.email</div>
</div>
<button ng-click="result()">OK</button>
function demo($scope) {
$scope.ui = {};
$scope.people = [{
name: 'Janis',
selected: false
}, {
name: 'Danyl',
selected: false
}, {
name: 'tymeJV',
selected: false
}];
$scope.selectPeople = function(people) {
people.selected = !people.selected;
};
$scope.result = function() {
$scope.ui.result = [];
angular.forEach($scope.people, function(value) {
if (value.selected) {
$scope.ui.result.push(value);
}
});
};
}
.recipient {
cursor: pointer;
}
.select {
color:green;
}
.recipient:hover {
background-color:blue;
}
<script src="https://code.angularjs.org/1.2.25/angular.js"></script>
<div ng-app ng-controller="demo">
<div class="recipient" ng-repeat="person in people" ng-click="selectPeople(person)" ng-class="{ select: person.selected }">
<div class="name">{{ person.name }}</div>
</div>
<button ng-click="result()">OK</button>
Result :
<ul>
<li ng-repeat="item in ui.result">{{ item.name }}</li>
</ul>
</div>
If you only want to show checked or unchecked you could just apply a filter, but you would need to toggle the filter value from undefined to true if you didn't wan't to get stuck not being able to show all again.
HTML:
<button ng-click="filterChecked()">Filter checked: {{ checked }}</button>
<div class="recipient" ng-repeat="person in people | filter:checked">
<input type='checkbox' ng-model="person.isChecked" />
<img ng-src="{{person.img}}" />{{ person.name }}
<div class="email">{{ person.email }}</div>
</div>
Controller:
// Apply a filter that shows either checked or all
$scope.filterChecked = function () {
// if set to true or false it will show checked or not checked
// you would need a reset filter button or something to get all again
$scope.checked = ($scope.checked) ? undefined : true;
}
If you want to get all that have been checked and submit as form data you could simply loop through the array:
Controller:
// Get a list of who is checked or not
$scope.getChecked = function () {
var peopleChkd = [];
for (var i = 0, l = $scope.people.length; i < l; i++) {
if ($scope.people[i].isChecked) {
peopleChkd.push(angular.copy($scope.people[i]));
// Remove the 'isChecked' so we don't have any DB conflicts
delete peopleChkd[i].isChecked;
}
}
// Do whatever with those checked
// while leaving the initial array alone
console.log('peopleChkd', peopleChkd);
};
Check out my fiddle here
Notice that person.isChecked is only added in the HTML.

Binding to a specific object in array with AngularJS

I have a collection of rooms in my $scope, with the structure:
$scope.model.rooms = [
{ RoomNumber: 1, Type: 'Single'},
{ RoomNumber: 3, Type: 'Single'},
{ RoomNumber: 5, Type: 'Double'},
{ RoomNumber: 6, Type: 'Single'},
{ RoomNumber: 12, Type: 'Double'}
];
I then create a 5x5 grid on my view as follows, and want to have the correct room type selected on the drop down, but I don't know how to do this binding properly.
<div data-ng-repeat="y in [1, 2, 3, 4, 5]" class="hotelRooms">
<div data-ng-repeat="x in [1, 2, 3, 4, 5]">
<h6>
Room #{{(y-1)*5+x}}
<select id="binType{{(y-1)*5+x}}" data-ng-model="model.rooms[/*WHAT DO I PUT HERE?*/].Type" data-ng-change="setRoomType((y-1)*5+x)">
<option value="Single">Single</option>
<option value="Double">Double</option>
</select>
</h6>
<div id="bin{{(y-1)*5+x}}" data-droppable="{{(y-1)*5+x}}" data-drop="addToRoom">
<div id="{{p.Id}}" data-draggable="" data-ng-repeat="p in model.participants | filter:{RoomNumber:(y-1)*5+x}">{{p.Name}}</div>
</div>
</div>
</div>
The array index isn't the same as the RoomNumber property.
I find it much more intuitive if you put all of your behavior into your controller. Your view just binds to those behaviors (a la MVVM). You get more control over your code this way and aren't at the mercy of {{binding syntax}} and its limitations.
I removed the drag and drop stuff, but here's how I got it to work. Notice you don't need the ngChange directive in the select because this way it's bound right to the room model Type property. So they stay in sync when you change it.
Here's a fiddle with the working code, or just see below: http://jsfiddle.net/854wk/7/
Controller:
function MyController($scope) {
$scope.calcBin = calcBin;
$scope.getRoomByBin = getRoomByBin;
function calcBin(row, col) {
return ((row - 1) * 5) + col;
};
function getRoomByBin(row, col) {
var bin = calcBin(row, col);
var foundRoom;
$scope.model.rooms.some(function(room) {
if (room.RoomNumber === bin)
{
foundRoom = room;
return true; // break
}
});
return foundRoom;
}
}
View:
<div ng-app>
<div ng-controller="MyController">
<div data-ng-repeat="y in [1, 2, 3, 4, 5]"
class="hotelRooms">
<div data-ng-repeat="x in [1, 2, 3, 4, 5]">
<h6>
Room #{{calcBin(y,x)}}
<select id="binType{{calcBin(y,x)}}"
data-ng-model="getRoomByBin(y,x).Type" >
<option value="Single">Single</option>
<option value="Double">Double</option>
</select>
Room Type is: {{getRoomByBin(y,x).Type}}
</h6>
</div>
</div>
</div>

Resources