I would like to use a check list and show the user the boxes she has checked.
I am using this framework: http://vitalets.github.io/angular-xeditable/#checklist . See his example 'Checklist' versus his example 'Select multiple'. However, I do not want to display a link with a comma separated string, i.e., join(', '). I would like each selection to appear beneath the previous, in an ordered list or similar.
Pretty much copied from his examples, here are the guts of my controller:
$scope.userFeeds = {
feeds: {}
};
$scope.feedSource = [
{ id: 1, value: 'All MD' },
{ id: 2, value: 'All DE' },
{ id: 3, value: 'All DC' }
];
$scope.updateFeed = function (feedSource, option) {
$scope.userFeeds.feeds = [];
angular.forEach(option, function (v) {
var feedObj = $filter('filter')($scope.feedSource, { id: v });
$scope.userFeeds.feeds.push(feedObj[0]);
});
return $scope.userFeeds.feeds.length ? '' : 'Not set';
};
And here is my html:
<div ng-show="eventsForm.$visible"><h4>Select one or more feeds</h4>
<span editable-select="feedSource"
e-multiple
e-ng-options="feed.id as feed.value for feed in feedSource"
onbeforesave="updateFeed(feedSource, $data)">
</span>
</div>
<div ng-show="!eventsForm.$visible"><h4>Selected Source Feed(s)</h4>
<ul>
<li ng-repeat="feed in userFeeds.feeds">
{{ feed.value || 'empty' }}
</li>
<div ng-hide="userFeeds.feeds.length">No items found</div>
</ul>
</div>
My problem is - display works with editable-select and e-multiple, but not with editable-checklist. Swap it out and nothing is returned.
To workaround, I have tried dynamic html as in here With ng-bind-html-unsafe removed, how do I inject HTML? but I have considerable difficulties getting the page to react to a changed scope.
My goal is to allow a user to select from a checklist and then to display the checked items.
Try this fiddle: http://jsfiddle.net/mr0rotnv/15/
Your onbeforesave will need to return false, instead of empty string, to stop conflict with the model update from xEditable. (Example has onbeforesave and model binding working on the same variable)
return $scope.userFeeds.feeds.length ? false : 'Not set';
If you require to start in edit mode add the attribute shown="true" to the surrounding form element.
Code for completeness:
Controller:
$scope.userFeeds = {
feeds: []
};
$scope.feedSource = [
{ id: 1, value: 'All MD' },
{ id: 2, value: 'All DE' },
{ id: 3, value: 'All DC' }
];
$scope.updateFeed = function (feedSource, option) {
$scope.userFeeds.feeds = [];
angular.forEach(option, function (v) {
var feedObj = $filter('filter')($scope.feedSource, { id: v });
if (feedObj.length) { // stop nulls being added.
$scope.userFeeds.feeds.push(feedObj[0]);
}
});
return $scope.userFeeds.feeds.length ? false : 'Not set';
};
Html:
<div ng-show="editableForm.$visible">
<h4>Select one or more feeds</h4>
<span editable-checklist="feedSource"
e-ng-options="feed.id as feed.value for feed in feedSource"
onbeforesave="updateFeed(feedSource, $data)">
</span>
</div>
<div ng-show="!editableForm.$visible">
<h4>Selected Source Feed(s)</h4>
<ul>
<li ng-repeat="feed in userFeeds.feeds">{{ feed.value || 'empty' }}</li>
<div ng-hide="userFeeds.feeds.length">No items found</div>
</ul>
</div>
Css:
(Used to give the "edit view" a list appearance)
.editable-input label {display:block;}
Also there is the option of using a filter if you do not need to do any validation or start in edit mode.
Controller:
$scope.user = { status: [2, 3] };
$scope.statuses = [
{ value: 1, text: 'status1' },
{ value: 2, text: 'status2' },
{ value: 3, text: 'status3' }
];
$scope.filterStatus = function (obj) {
return $scope.user.status.indexOf(obj.value) > -1;
};
HTML:
<a href="#" editable-checklist="user.status" e-ng-options="s.value as s.text for s in statuses">
<ol>
<li ng-repeat="s in statuses | filter: filterStatus">{{ s.text }}</li>
</ol>
</a>
Related
How can I filter an ng-repeat to show all items where a certain columnfield is an empty string? When I try this by typing nothing in the field it always seem to give the full list (wich is expected). I only want to see the person with id 1. How can I adjust the filter that a certain character in the inputfield makes the ng repeat filter on empty fields for the name column.
FiddleJs Example
My view:
<div class="panel-heading">
<h3>Filtered by {{filterValue}}</h3>
<input ng-change="filter()" ng-model="filterValue"/>
</div>
<div class="panel-body">
<ul class="list-unstyled">
<li ng-repeat="p in filteredPeople">
<h4>{{p.name}} ({{p.age}}) id: {{p.id}}</h4>
</li>
</ul>
</div>
Controller:
var people = [{
name: '',
age: 32,
id: 1
}, {
name: 'Jonny',
age: 34,
id: 2
}, {
name: 'Blake',
age: 28,
id: 3
}, {
name: 'David',
age: 35,
id: 4
}];
$scope.filter = function (value) {
$scope.filteredPeople = $filter('filter')(people, {
name: $scope.filterValue
});
}
$scope.people = people.slice(0);
Delete your $scope.filter() function in the controller and the ng-change="filter()" in your view. You should change var people array to $scope.people. You also need to delete the line $scope.people = people.slice(0);.
Create a filter function in your controller to only return people whose name property is empty if $scope.filterValue is empty:
$scope.emptyFilter = function(person) {
if ($scope.filterValue.length === 0) {
if (person.name.length === 0) {
return person;
}
} else {
return person;
}
};
Next, update your ng-repeat with the following:
<li ng-repeat="p in people | filter:emptyFilter | filter:{name: filterValue}">
I have an unordered list that is being filtered on when a select option is selected. My problem is that when 'ALL' is selected nothing displays because the value does not match the item.status of any of my list items. Is there a way of adding || which will then filter on item.status or 'ALL'?
Below are the values that are in the select. One of these values is also referenced for each list item as item.status
app.value('filterSavedList', pageOptions = [
{
value: 'ALL',
label: 'All'
},
{
value: 'NEW',
label: 'Not started'
},
{
value: 'STARTED',
label: 'In progress'
},
{
value: 'COMPLETED',
label: 'Completed'
}
]);
My select and my unordered list.
<select ng-model="filter" ng-options="item.value as item.label for item in status">
</select>
<ul>
<li ng-repeat="item in assignments | filter: { status : filter }">
//do stuff
</li>
</ul>
You simply need to set the status value to '' (empty string), and make sure filter (i.e. the model of the select box) is initialized to one of the 4 values (i.e. initialized to '', if the option All must be pre-selected)
See http://plnkr.co/edit/mJtQnwA3aQhpT4WN62jj?p=preview for a complete example.
You can also create a custom filter that does normal filtering by property and also takes care of the ALL possibility in status:
.filter('filterStatus', function () {
return function (items, status) {
if(status === 'ALL') {
return items;
}
else {
var itemsToReturn = [];
for(var i=0,x=items.length;i<x;i++) {
if(items[i].status === status) {
itemsToReturn.push(items[i]);
}
}
return itemsToReturn;
}
};
});
Then in HTML:
<ul>
<li ng-repeat="item in assignments | filterStatus: filter">
<!-- do stuff -->
</li>
</ul>
I need to show object only if one of it's properties equals to array.
I have a controller in app.js:
app.controller('checkBoxController', function ($scope) {
$scope.ingredients= [
{label: 'Egg', value: 1},
{label: 'Milk', value: 2},
$scope.selection=[];
$scope.toggleSelection = function toggleSelection(ingredientLabel) {
var idx = $scope.selection.indexOf(ingredientLabel);
if (idx > -1) {
$scope.selection.splice(idx, 1);
}
else {
$scope.selection.push(ingredientLabel);
}
};
});
and an html code for it:
<span style="color:black;" class="selected-item">Selected Items:<span>
<div ng-repeat="label in selection" class="selected-item">
</div>
<div class="list-group">
<div class="list-group-item" ng-repeat="product in meals.products" ng-show="product.contents==selection">
<h1>{{product.name}}</h1>
<meal-gallery></meal-gallery>
<meal-tabs></meal-tabs>
</div>
</div>
And I Have { name: 'Scrambled Egg', contents: "Egg"} in array of products. So I need to show product if it's contents equals to selected ingredients.
I do not have problems when it is only one ingredient like "Egg", but if I need contents of two equal to selected?
It would be best to use a custom filter.
If you add lodash to your application, you can create a filter that will preform a following operation:
angular.module('common', [])
.filter('canBeMadeFrom', function() {
return function(product, ingredients) {
return _.intersection(product.contents, ingredients).length == product.contents.length';
};
});
this will return true if all of products contents are contained in ingredients
use it like this
ng-repeat='product in products | canBeMadeFrom:ingredients'
Use a filter.
<div ng-repeat=product in products |filter: product.a === a && product.b === b>
You can also use a function for filter. It's a function that takes in an item and returns Boolean
I have a AngularJS directive that allows users to select a values from a list to filter on. Pretty simple concept which is represented here:
Problem is when I click one of the checkboxes they all select unintended. My directive is pretty simple so I'm not sure why this is happening. The code around the selection and checkboxes is as follows:
$scope.tempFilter = {
id: ObjectId(),
fieldId: $scope.available[0].id,
filterType: 'contains'
};
$scope.toggleCheck = function (id) {
var values = $scope.tempFilter.value;
if (!values || !values.length) {
values = $scope.tempFilter.value = [];
}
var idx = values.indexOf(id);
if (idx === -1) {
values.push(id);
} else {
values.splice(idx, 1);
}
};
$scope.valuesListValues = function (id) {
return $scope.available.find(function (f) {
return f.id === id;
}).values;
};
and the data resembles:
$scope.available = [{
id: 23,
name: 'Store'
values: [
{ id: 124, name: "Kansas" },
{ id: 122, name: "Florida" }, ... ]
}, ... ]
the view logic is as follows:
<ul class="list-box">
<li ng-repeat="val in valuesListValues(tempFilter.fieldId)">
<div class="checkbox">
<label ng-click="toggleCheck(val.id)">
<input ng-checked="tempFilter.value.indexOf(val.id) === -1"
type="checkbox"> {{val.name}}
</label>
</div>
</li>
</ul>
First off, it toggleCheck fires twice but populates the correct data ( second time given my code it removes it though ).
After the second fire, it checks all boxes... Any ideas?
Perhaps its that the local variable doesn't get reassigned to the property of the scope property used in the view. Since your values are then non-existent and not found, the box is checked.
$scope.tempFilter.value = values
I took the interface concept you were after and created a simpler solution. It uses a checked property, found in each item of available[0].values, as the checkbox model. At the top of the list is a button that clears the selected items.
JavaScript:
function DataMock($scope) {
$scope.available = [{
id: 23,
name: 'Store',
values: [{
id: 124,
name: "Kansas"
}, {
id: 122,
name: "Florida"
}]
}];
$scope.clearSelection = function() {
var values = $scope.available[0].values;
for (var i = 0; i < values.length; i++) {
values[i].checked = false;
}
};
}
HTML:
<body ng-controller="DataMock">
<ul class="list-box">
<li>
<button ng-click="clearSelection()">Clear Selection</button>
</li>
<li ng-repeat="val in available[0].values">
<div class="checkbox">
<label>
<input ng-model="val.checked"
type="checkbox" /> {{val.name}}
</label>
</div>
</li>
</ul>
</body>
Demo on Plunker
The repeat that I used to grab the values based on the id, was the problem area.
<li ng-repeat="val in valuesListValues(tempFilter.fieldId)">
removing that and simple listening and setting a static variable resolved the problem.
$scope.$watch('tempFilter.fieldId', function () {
var fId = $scope.tempFilter.fieldId;
if ($scope.isFieldType(fId, 'valuesList')) {
$scope.valuesListValues = $scope.valuesListValues(fId);
}
}, true);
});
and then in the view:
ng-repeat="value in valuesListValues"
Is there any function or ng-something to check if any of the displayed Checkboxes are checked?
I have the values through the ng-click="function()" and pass the values through. I can go by foot and check my array if any value is inside.
I want to activate/deactivate the "next"-button if any Checkbox is
checked.
What's the easiest way?
If you don't want to use a watcher, you can do something like this:
<input type='checkbox' ng-init='checkStatus=false' ng-model='checkStatus' ng-click='doIfChecked(checkStatus)'>
You can do something like:
function ChckbxsCtrl($scope, $filter) {
$scope.chkbxs = [{
label: "Led Zeppelin",
val: false
}, {
label: "Electric Light Orchestra",
val: false
}, {
label: "Mark Almond",
val: false
}];
$scope.$watch("chkbxs", function(n, o) {
var trues = $filter("filter")(n, {
val: true
});
$scope.flag = trues.length;
}, true);
}
And a template:
<div ng-controller="ChckbxsCtrl">
<div ng-repeat="chk in chkbxs">
<input type="checkbox" ng-model="chk.val" />
<label>{{chk.label}}</label>
</div>
<div ng-show="flag">I'm ON when band choosed</div>
</div>
Working: http://jsfiddle.net/cherniv/JBwmA/
UPDATE: Or you can go little bit different way , without using $scope's $watch() method, like:
$scope.bandChoosed = function() {
var trues = $filter("filter")($scope.chkbxs, {
val: true
});
return trues.length;
}
And in a template do:
<div ng-show="bandChoosed()">I'm ON when band choosed</div>
Fiddle: http://jsfiddle.net/uzs4sgnp/
If you have only one checkbox, you can do this easily with just ng-model:
<input type="checkbox" ng-model="checked"/>
<button ng-disabled="!checked"> Next </button>
And initialize $scope.checked in your Controller (default=false). The official doc discourages the use of ng-init in that case.
Try to think in terms of a model and what happens to that model when a checkbox is checked.
Assuming that each checkbox is bound to a field on the model with ng-model then the property on the model is changed whenever a checkbox is clicked:
<input type='checkbox' ng-model='fooSelected' />
<input type='checkbox' ng-model='baaSelected' />
and in the controller:
$scope.fooSelected = false;
$scope.baaSelected = false;
The next button should only be available under certain circumstances so add the ng-disabled
directive to the button:
<button type='button' ng-disabled='nextButtonDisabled'></button>
Now the next button should only be available when either fooSelected is true or baaSelected is true and we need to watch any changes to these fields to make sure that the next button is made available or not:
$scope.$watch('[fooSelected,baaSelected]', function(){
$scope.nextButtonDisabled = !$scope.fooSelected && !scope.baaSelected;
}, true );
The above assumes that there are only a few checkboxes that affect the availability of the next button but it could be easily changed to work with a larger number of checkboxes and use $watchCollection to check for changes.
This is re-post for insert code also.
This example included:
- One object list
- Each object hast child list.
Ex:
var list1 = {
name: "Role A",
name_selected: false,
subs: [{
sub: "Read",
id: 1,
selected: false
}, {
sub: "Write",
id: 2,
selected: false
}, {
sub: "Update",
id: 3,
selected: false
}],
};
I'll 3 list like above and i'll add to a one object list
newArr.push(list1);
newArr.push(list2);
newArr.push(list3);
Then i'll do how to show checkbox with multiple group:
$scope.toggleAll = function(item) {
var toogleStatus = !item.name_selected;
console.log(toogleStatus);
angular.forEach(item, function() {
angular.forEach(item.subs, function(sub) {
sub.selected = toogleStatus;
});
});
};
$scope.optionToggled = function(item, subs) {
item.name_selected = subs.every(function(itm) {
return itm.selected;
})
$scope.txtRet = item.name_selected;
}
HTML:
<li ng-repeat="item in itemDisplayed" class="ng-scope has-pretty-child">
<div>
<ul>
<input type="checkbox" class="checkall" ng-model="item.name_selected" ng-click="toggleAll(item)"><span>{{item.name}}</span>
<div>
<li ng-repeat="sub in item.subs" class="ng-scope has-pretty-child">
<input type="checkbox" kv-pretty-check="" ng-model="sub.selected" ng-change="optionToggled(item,item.subs)"><span>{{sub.sub}}</span>
</li>
</div>
</ul>
</div>
<span>{{txtRet}}</span>
</li>
Fiddle: example
I've a sample for multiple data with their subnode
3 list , each list has attribute and child attribute:
var list1 = {
name: "Role A",
name_selected: false,
subs: [{
sub: "Read",
id: 1,
selected: false
}, {
sub: "Write",
id: 2,
selected: false
}, {
sub: "Update",
id: 3,
selected: false
}],
};
var list2 = {
name: "Role B",
name_selected: false,
subs: [{
sub: "Read",
id: 1,
selected: false
}, {
sub: "Write",
id: 2,
selected: false
}],
};
var list3 = {
name: "Role B",
name_selected: false,
subs: [{
sub: "Read",
id: 1,
selected: false
}, {
sub: "Update",
id: 3,
selected: false
}],
};
Add these to Array :
newArr.push(list1);
newArr.push(list2);
newArr.push(list3);
$scope.itemDisplayed = newArr;
Show them in html:
<li ng-repeat="item in itemDisplayed" class="ng-scope has-pretty-child">
<div>
<ul>
<input type="checkbox" class="checkall" ng-model="item.name_selected" ng-click="toggleAll(item)" />
<span>{{item.name}}</span>
<div>
<li ng-repeat="sub in item.subs" class="ng-scope has-pretty-child">
<input type="checkbox" kv-pretty-check="" ng-model="sub.selected" ng-change="optionToggled(item,item.subs)"><span>{{sub.sub}}</span>
</li>
</div>
</ul>
</div>
</li>
And here is the solution to check them:
$scope.toggleAll = function(item) {
var toogleStatus = !item.name_selected;
console.log(toogleStatus);
angular.forEach(item, function() {
angular.forEach(item.subs, function(sub) {
sub.selected = toogleStatus;
});
});
};
$scope.optionToggled = function(item, subs) {
item.name_selected = subs.every(function(itm) {
return itm.selected;
})
}
jsfiddle demo