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.
Related
I'm currently using a custom filter to display a name when a user id is displayed. So selected_user might be 5, so it then displays "bob" instead of "5":
{{ selected_user | display_name:users }}
The users object contains the entire users table.
The code:
angular.module('myApp', []);
function xCtrl($scope) {
$scope.users = [
{"id":1, "name":"joe"},
{"id":5, "name":"bob"},
{"id":10, "name":"charlie"},
];
$scope.select_user = function(user) {
$scope.selected_user = user;
}
}
angular.module('myApp').filter("display_name", function () {
return function (user_id, users) {
if(user_id) {
return(users[users.map(function(x) { return x.id; }).indexOf(user_id)].name);
}
}
});
This works fine, but it feels like I am doing this inefficiently by passing the entire users object to the filter each time a name is displayed. Is there a better way to do this with filters or are filters the wrong approach?
Demo: http://jsfiddle.net/h2rn3qnw/
One approach is to have the ng-click directive return the $index:
<div ng-repeat="user_data in users"
ng-click="select($index)" class="selection">
{{ user_data.id }} - {{ user_data.name }} - {{$index}}
</div>
$scope.select = function(index) {
$scope.selection = index;
};
Selected User ID: {{ users[selection].id }}<br>
Selected User Name: {{ users[selection].name }}
The DEMO
angular.module('myApp', [])
.controller("xCtrl", function xCtrl($scope) {
$scope.users = [
{"id":1, "name":"joe"},
{"id":5, "name":"bob"},
{"id":10, "name":"charlie"},
];
$scope.select = function(index) {
$scope.selection = index;
};
})
.selection { color:blue; cursor:pointer; }
<script src="//unpkg.com/angular/angular.js"></script>
<div ng-app='myApp'>
<div ng-controller="xCtrl">
Users:<br>
<div ng-repeat="user_data in users"
ng-click="select($index)" class="selection">
{{ user_data.id }} - {{ user_data.name }} - {{$index}}
</div> <!-- ng-repeat -->
<hr>
Selected User ID: {{ users[selection].id }}<br>
Selected User Name: {{ users[selection].name }}
</div> <!-- ng-controller -->
</div> <!-- ng-app -->
I have a roles list that filter a permissions list. The permissions list has a checkbox indicating that it is selected.
Each role has a list of associated permissions. When a role is selected, all available permissions are displayed and those already associated with them will be checked. By clicking on the checkbox of each permission you can associate or desesociate it.
But the select and unselect permission action does not work properly. I can not figure out what the problem. Can someone help me ? Thanks!!!
Code in Plunker
Page code
<div class="panel-body">
<div class="form-group">
<div class="col-md-6">
<div class="list-group">
<a ng-click="selectRole(role)" ng-repeat="role in model.roles" class="list-group-item" ng-class="{active: role.id == model.selectedRole.id}">{{role.name}}</a>
</div>
</div>
<div class="col-md-6">
<div class="list-group">
<a ng-repeat="permission in model.permissions" class="list-group-item">{{permission.name}} <input type="checkbox" class="pull-right" ng-checked="isSelected(permission.id) > -1" ng-click="clickPermission(permission)" ng-class="{active: permission.id == model.selectedPermission.id}" />
</a>
</div>
</div>
</div>
</div>
Controller code
app.controller('PermissionsToRoleController', function($scope) {
$scope.model = {
roles: [],
permissions: [],
selectedRole: null,
selectedPermission: null
};
$scope.selectRole = function(role) {
$scope.model.selectedRole = role;
}
var findRoles = function() {
$scope.model.roles = [{id: 1, name: 'ADMIN', permissions: [{id: 1, name:'MASTER'}] },
{id: 2, name: 'USER', permissions: [] }
];
$scope.model.permissions = [{id: 1, name: 'MASTER'}];
$scope.model.selectedRole = $scope.model.roles[0];
};
$scope.clickPermission = function(permission) {
$scope.model.selectedPermission = permission;
var idx = $scope.isSelected(permission.id);
if (idx > -1) {
$scope.model.selectedRole.permissions.splice(idx, 1);
} else {
$scope.model.selectedRole.permissions.push(permission);
}
};
$scope.isSelected = function(permissionId) {
for (var i = 0; i < $scope.model.selectedRole.permissions.length ; i++) {
if ($scope.model.selectedRole.permissions[i].id === permissionId) {
return i;
}
}
return -1;
}
findRoles();
});
The problem I found being the checkbox, while functions properly, the display won't "uncheck" when you click on it.
This can be fixed by changing the surrounding element to span instead of a
<span ng-repeat="permission in model.permissions" class="list-group-item">{{permission.name}}
<input type="checkbox" class="pull-right" ng-checked="isSelected(permission.id) > -1" ng-click="clickPermission(permission)" ng-class="{active: permission.id == model.selectedPermission.id}" />
</span>
I'm not sure about the reason behind this, though.
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 trying to show list of questions and their choices by nested ng-repeat, I have seen plenty of similar questions but still could not fix my issue. My issue here is I could see the list of questions but the choices are not getting displayed and in the developer tools I could only see the commented ng-repeat line in place of choices.
Here is my View
<div ng-repeat ="question in questions track by $index" class="panel panel-default" ng-show="showQuestions">
<div class="panel-heading">
<div class="panel-title">
<a href="div#{{$index}}" class="accordion-toggle" data-toggle="collapse" data-parent="#accordion" >
{{question.QuestionTxt}}
</a>
<div class="row height"></div>
<div class="row" ng-show="question.QuestionTypeTxt == 'RadioButton'">
<div class="col-xs-3" ng-repeat ="answer in questions.QuestionAnswers track by $index">
<input type="radio" ng-model="selectedChoice.choice" ng-value="{{answer.AnswerTxt}}" name="{{question.QuestionTxt}}"/>{{answer.AnswerTxt}}
</div>
</div>
<div class="row" ng-show="question.QuestionTypeTxt == 'Checkbox'">
<div class="col-xs-3" ng-repeat ="answer in questions.QuestionAnswers track by $index">
<input type="checkbox" ng-model="selectedChoice.choice" ng-value="{{answer.AnswerTxt}}" name="{{question.QuestionTxt}}"/>{{answer.AnswerTxt}}
</div>
</div>
</div>
</div>
</div>
Here is my Controller
$scope.questions = [];
$scope.selectedChoice = { choice:"" };
$scope.addQuestions = function () {
$scope.showQuestions = true;
rmat3Service.getQuestionsForSection().then(function (data) {
angular.forEach(data,function(a) {
$scope.questions.push(a);
});
});
}
This is my Json data:
var questions = new List<Question>();
var answers = new List<QuestionAnswer>();
answers.Add(new QuestionAnswer()
{
AnswerTxt = "Yes",
});
answers.Add(new QuestionAnswer()
{
AnswerTxt = "No"
});
answers.Add(new QuestionAnswer()
{
AnswerTxt = "Yes Verified"
});
answers.Add(new QuestionAnswer()
{
AnswerTxt = "Not Applicable"
});
questions.Add(new Question()
{
QuestionId = 1,
QuestionTxt = "Are aisles clear of product on the floor?",
QuestionTypeTxt = "RadioButton",
QuestionAnswers = answers
});
questions.Add(new Question()
{
QuestionId = 2,
QuestionTxt = "Automated Car Wash",
QuestionTypeTxt = "Checkbox",
QuestionAnswers = answers
});
return Json(questions, JsonRequestBehavior.AllowGet);
The issue is that you're attempting to loop questions.QuestionAnswers which doesn't exist. It should be question.QuestionAnswers:
<div class="col-xs-3" ng-repeat ="answer in question.QuestionAnswers track by $index">
I'm developoing a web app and stuck here:
Part of the HTML:
<div class="input-group">
<select name="select" class="form-control input-group-select" ng-options="key as key for (key , value) in pos" ng-model="word.pos" ng-change="addPos()">
<option value="">Choose a POS</option>
</select>
<span class="sort"><i class="fa fa-sort"></i></span>
</div>
<ul class="listGroup" ng-show="_pos.length > 0">
<li class="list" ng-repeat="item in _pos track by $index">
<span>
{{item.pos}}
<span class="btn btn-danger btn-xs" ng-click="delPos($index)">
<span class="fa fa-close"></span>
</span>
</span>
<!-- I wanna add the input which can add more list item to the item.pos-->
<div class="input-group">
<a class="input-group-addon add" ng-class=" word.newWordExp ? 'active' : ''" ng-click="addItemOne()"><span class="fa fa-plus"></span></a>
<input type="text" class="form-control exp" autocomplete="off" placeholder="Add explanation" ng-model="word.newWordExp" ng-enter="addExpToPos()">
{{word.newWordExp}}
</div>
</li>
</ul>
Part of the js:
$scope._pos = [];
$scope.addPos = function () {
console.log("You selected something!");
if ($scope.word.pos) {
$scope._pos.push({
pos : $scope.word.pos
});
}
console.dir($scope._pos);
//console.dir($scope.word.newWordExp[posItem]);
};
$scope.delPos = function ($index) {
console.log("You deleted a POS");
$scope._pos.splice($index, 1);
console.dir($scope._pos);
};
$scope.addItemOne = function (index) {
//$scope.itemOne = $scope.newWordExp;
if ($scope.word.newWordExp) {
console.log("TRUE");
$scope._newWordExp.push({
content: $scope.word.newWordExp
});
console.dir($scope._newWordExp);
$scope.word.newWordExp = '';
} else {
console.log("FALSE");
}
};
$scope.deleteItemOne = function ($index) {
$scope._newWordExp.splice($index, 1);
};
So, what am I wannt to do is select one option and append the value to $scope._pos, then display as a list with all of my selection.
And in every list item, add an input filed and add sub list to the $scope._pos value.
n.
explanation 1
explanation 2
explanation 3
adv.
explanation 1
explanation 2
So I don't know how to generate dynamic ng-model and use the value in javascript.
Normaly should like ng-model="word.newExplanation[item]" in HTML, but in javascript, $scope.word.newExplanation[item] said "item is not defined".
can any one help?
If I've understood it correclty you could do it like this:
Store your lists in an array of object this.lists.
The first object in the explanation array is initialized with empty strings so ng-repeat will render the first explanation form.
Then loop over it with ng-repeat. There you can also add dynamically the adding form for your explanation items.
You can also create append/delete/edit buttons inside the nested ng-repeat of your explanation array. Append & delete is already added in the demo.
Please find the demo below or in this jsfiddle.
angular.module('demoApp', [])
.controller('appController', AppController);
function AppController($filter) {
var vm = this,
explainTmpl = {
name: '',
text: ''
},
findInList = function (explain) {
return $filter('filter')(vm.lists, {
explanations: explain
})[0];
};
this.options = [{
name: 'option1',
value: 0
}, {
name: 'option2',
value: 1
}, {
name: 'option3',
value: 2
}];
this.lists = [];
this.selectedOption = this.options[0];
this.addList = function (name, option) {
var list = $filter('filter')(vm.lists, {
name: name
}); // is it in list?
console.log(name, option, list, list.length == 0);
//vm.lists
if (!list.length) {
vm.lists.push({
name: name,
option: option,
explanations: [angular.copy(explainTmpl)]
});
}
};
this.append = function (explain) {
console.log(explain, $filter('filter')(vm.lists, {
explanations: explain
}));
var currentList = findInList(explain);
currentList.explanations.push(angular.copy(explainTmpl));
}
this.delete = function (explain) {
console.log(explain);
var currentList = findInList(explain),
index = currentList.explanations.indexOf(explain);
if (index == 0 && currentList.explanations.length == 1) {
// show alert later, can't delete first element if size == 1
return;
}
currentList.explanations.splice(index, 1);
};
}
AppController.$inject = ['$filter'];
<link href="http://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css" rel="stylesheet"/>
<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>
<div ng-app="demoApp" ng-controller="appController as ctrl">
<select ng-model="ctrl.selectedOption" ng-options="option.name for option in ctrl.options"></select>
<input ng-model="ctrl.listName" placeholder="add list name" />
<button class="btn btn-default" title="add list" ng-click="ctrl.addList(ctrl.listName, ctrl.selectedOption)"><i class="fa fa-plus"></i>
</button>
<div class="list-group">Debug output - current lists:<pre>{{ctrl.lists|json:2}}</pre>
<div class="list-group-item" ng-repeat="list in ctrl.lists">
<h2>Explanations of list - {{list.name}}</h2>
<h3>Selected option is: {{ctrl.selectedOption}}</h3>
<div class="list-group" ng-repeat="explain in list.explanations">
<div class="list-group-item">
<p class="alert" ng-if="!explain.title">No explanation here yet.</p>
<div class="well" ng-if="explain.title || explain.text">
<h4>
{{explain.title}}
</h4>
<p>{{explain.text}}</p>
</div>Title:
<input ng-model="explain.title" placeholder="add title" />Text:
<input ng-model="explain.text" placeholder="enter text" />
<button class="btn btn-primary" ng-click="ctrl.append(explain)">Append</button>
<button class="btn btn-primary" ng-click="ctrl.delete(explain)">Delete</button>
</div>
</div>
</div>
</div>
</div>