Disable check-boxes using a function with AngularJS - angularjs

I have a question about how to uncheck check-boxes inside ng-repeat, when the ng-model is already in use?
This is the construction:
The object:
$scope.wines = [
{ "name": "Wine a", "type": "white", "country": "italie", "style": "medium" },
{ "name": "Wine a", "type": "white", "country": "france", "style": "light" },
{ "name": "Wine a", "type": "white", "country": "france", "style": "sweet" }
];
$scope.winetypes = {white : true, red: true};
$scope.whitetypes = {light : false,medium : false,sweet : false};
});
HTML
<li ng-repeat="(type, value) in winetypes">
<input type="checkbox" ng-model="winetypes[type]" /> {{type}}
</li>
<li ng-repeat="(style, value) in whitetypes">
<input type="checkbox" ng-model="whitetypes[style]" /> {{style}}
</li>
<ul>
<li ng-repeat="wine in wines | winetypefilter:winetypes |whitefilter:whitetypes">
{{wine.name}} is a {{wine.type}} with {{wine.style}} style from {{wine.country}}
</li>
</ul>
My wish: the check-boxes linked to the whitetypes (light, medium, sweet) would be automatically unchecked, when the white check-box would be unchecked. I guess ng-model can't be used to achieve my wishes, because it's already in use.
I tried without success:
$scope.white= function() {
if($scope.winetypes.white = false) {
return $scope.whitetypes = {light: false, medium: false, sweet: false}
};
$scope.white;
The demo: http://plnkr.co/edit/nIQ2lkiJJY9MwJKHrqOk?p=preview

first decide what action you want...
You want to change a checkbox model and it's value should effect
other checkbox values...
so first solutions that come to my minds are...
ng-change (because your wish is about changing a checkbox attribute)
ng-click (for changing checkbox attribute you should click that input)
ng-checked (set condition to be checked or unchecked)
ok let's move on our solution... After analysing these three (there can be more solutions) ng-change is best for this scenario because it guarantees that binded fucntion will be execute after user changed value of checkbox... for more details check official docs
first edit your html...
<li ng-repeat="(type, value) in winetypes">
<input type="checkbox" ng-model="winetypes[type]" ng-change="disableRelatedStyles(type, winetypes[type])"/> {{type}}
</li>
and add our new function (disableRelatedStyles) to our controller...
$scope.disableRelatedStyles = function (type, value) {
if (type == 'white' && !value) {
for(var style in $scope.whitetypes) {
$scope.whitetypes[style] = false;
}
}
};
and finally a working PLUNKER...

What you could do is use ng-click and $timeout to handle every click to the white checkbox.
$scope.click_handler = function (type) {
if (type == 'white') {
$timeout(function () {
if ($scope.winetypes[type] === false) {
$scope.wines.forEach(function (e) {
if (e.type == 'white') {
$scope.whitetypes[e.style] = false;
}
})
}
})
}
};
The $timeout is necessary since we want to wait for ng-model to update first. Make sure you are injecting $timeout into the controller.
in markup
<input type="checkbox" ng-click="click_handler(type)" ng-model="winetypes[type]" /> {{type}}
Here is a working Plunker

Related

How to remove initial blank option and select <option> value when using ng-repeat or ng-options?

Angular newbie. Filtering json data returned via dataservice, and filter is done via dropdown. What i would like to do is a combination of things:
I would like to remove the initial blank value returned via Angular;
I would also like to have it pre-select a value by default that is not
included in my data object (in my case, returning all objects, added as a select option via my html); and
I would like to have that initial default value displayed when the
page is rendered.
I can remove the initial blank, but can't get that to incorporate the option I'm including.
I've looked into doing this with ng-repeat and ng-options, and can set the default value to one of the objects in my json via ng-options, but that doesn't seem to allow me to add in an option that doesn't exist in the data. Since I don't have a group that returns all values (and think it'd be best not to, since it that will make my data file much larger), adding that in as an option seemed the best way to do it.
There are many threads out there on how to remove the blank value returned for Angular (e.g. Empty first element in dropdown list and
Angular JS Remove Blank option from Select Option, etc.). I also see how to pre-select a value via ng-init, but that seems to require the value be a part of my data object, and not an option added in post-hoc via select option as I've done. Further, I see how to pre-select an empty data value via ng-options (e.g. http://ng-learn.org/2013/11/Draw_a_select_with_default_option/) but that doesn't seem to allow me to add in a data value which would return all data objects. When I add ng-selected='true' to my option data value, it appears to be selected when the page loads, but then that value disappears and the select dropdown is rendered as ng-pristine per developer tools. Not sure what I'm missing.
Working plunk here. As is, it has the initial blank, although again, you can see that "Show All" is displayed in the drop down when the page first loads but that it goes away. Again, I would like to remove the blank and select the option as the default value, and have that displayed in the dropdown so people know that's being rendered.
Thanks for any assistance!
html:
<div>
<div>
<form action="">
Group:
<select name="groups" id="grp" ng-model="groupid" ng-change="selectGroup()">
<option value="0" ng-selected="true">Show All</option>
<option ng-repeat="option in groups" value="{{option.ID}}" ng-selected="$first">{{option.name}}
</option>
</select>
</form>
</div>
<div>
<form action="">
Asset:
<select name="assets" id="assets" ng-model="selectedAsset">
<option ng-repeat="option in assets | filter: myFilter" value="{{option.ID}}">{{option.driverName}}</option>
</select>
</form>
</div>
</div>
filter:
$scope.myFilter = function(val, i, a) {
if($scope.groupid==0){
return true;
};
var m = false;
var grp = angular.fromJson($scope.selectedGroup);
angular.forEach(grp.members, function(v, k){
if(val.vpkDeviceID == v.vpkDeviceID){
m = true;
}
}, m);
return m;
};
$scope.selectedAsset = {};
$scope.groupid = 0;
$scope.selectedGroup = {};
$scope.selectGroup = function(){
var grp = [];
angular.forEach($scope.groups, function(v,i){
if($scope.groupid == v.ID){
$scope.selectedGroup = v;
}
})
}
json:
{
"assets": [
{
"deviceName": "vehicle 25",
"vpkDeviceID": 352964050744425,
"driverName": "Mike Smith"
},
{
"deviceName": "vehicle 52",
"vpkDeviceID": 352599041910352,
"driverName": "John Doe"
},
{
"deviceName": "vehicle 11",
"vpkDeviceID": 862170016156711,
"driverName": "Sarah Johnson"
},
{
"deviceName": "vehicle 28",
"vpkDeviceID": 862193020453528,
"driverName": "Eleanor Petit"
}
],
"groups":
[
{"ID": 1, "name": "nairobi", "members": [{"vpkDeviceID": 352964050744425}, {"vpkDeviceID": 352599041910352}, {"vpkDeviceID": 862170016156711}]},
{"ID": 2, "name": "karen", "members": [{"vpkDeviceID": 352964050744425}, {"vpkDeviceID": 352599041910352}]},
{"ID": 3, "name": "langata", "members": [{"vpkDeviceID": 352599041910352}, {"vpkDeviceID": 862170016156711}, {"vpkDeviceID": 862193020453528}]},
{"ID": 4, "name": "downtown", "members": [{"vpkDeviceID": 352964050744425}, {"vpkDeviceID": 862170016156711}]},
{"ID": 5, "name": "westlands", "members": [{"vpkDeviceID": 862193020453528}]}
]
}
The solution is simple: use ng-options, and bind to an object rather than an ID. Add a single option with a blank value to the select in order to display your "Show all" option.
Here's an updated plunkr: http://plnkr.co/edit/E8I6D6Ti3Kzw1eukuRBQ?p=preview
Key parts:
<select name="groups" id="grp" ng-model="selectedGroup" ng-options="group.name for group in groups">
<option value="">Show All</option>
</select>
$scope.myFilter = function(val, i, a) {
if(!$scope.selectedGroup){
return true;
}
var m = false;
var grp = $scope.selectedGroup;
angular.forEach(grp.members, function(v, k){
if(val.vpkDeviceID == v.vpkDeviceID){
m = true;
}
}, m);
return m;
};
No need to use ng-repeat. No need for a selectGroup() function. No need for ng-selected. No need for angular.toJson(). No need for a groupid in the scope.

AngularJS how to get and edit calculated input ng-model value related to other input value

I am trying to make some currency exchange system SPA based on AngularJS.
There should be several inputs that get currency data from json (with ng-repeat) and convert currency rate depending on active input value.
{
"currencies": [
{
"name":"EUR",
"rate": 1,
"active": "no"
},{
"name": "PLN",
"rate": 4.1028,
"active": "no"
}, {
"name": "USD",
"rate": 1.1239,
"active": "no"
}
]
}
<div ng-repeat='cur in main.currencies'>
<label>{{cur.name}}</label>
<input type="number" min="0"
ng-model="cur.result"
ng-init='cur.result = ""'
ng-click='main.clear();'
ng-focus='main.active = cur; cur.active = true';
ng-blur='cur.active = false';
>
</div>
How could I input 1 value on active (focused) input and get calculated values on other inputs. I am very new to AngularJS and want to learn it with practical exercises.
Other values should follow such logic: cur.value = main.active.value / main.active.rate * cur.rate.
But if I try instead of ng-model="cur.result":
ng-model="cur.result = main.active ? cur.result : cur.result/main.active.rate*cur.rate"
I can't write anything in input
Maybe I miss some ng*... in input properties, but as far I know if I use ng-model I should not use ng-name and ng-value...
try this JS:
angular.module('app',[]);
angular.module('app').controller('RateCtrl', RateCtrl);
function RateCtrl($scope){
var vm = $scope;
vm.cur = {};
vm.currencies = {/* your object */}
vm.setRate = function(model, rate){
return // your javascript
}
}
The HTML
<div ng-controller="RateCtrl as main">
<div ng-repeat="currency in main.currencies">
<label>{{currency.name}}</label>
<!-- Fyi, we are in an ng-repeat so there is an isolated scope. Sometimes '$parent.' must come before the objects outside ng-repeat -->
<input ng-model="main.cur.result" ng-focus="main.setRate(main.cur.result, currency.rate)">
</div>
</div>
This is one very basic way to manipulate the ng-model object. Alternatives include using Angular's filters, watchers, or decorators.

Set the selected option by value in the Kendo DropDownList

I have a kendo ui dropdownlist with angularjs in my html:
<select kendo-drop-down-list="dropdownlistCatalogs" k-options="optionsDropDownListCatalogs" data-role="dropdownlist" style="display: none;">
<option value="2" selected="selected">Test1</option>
<option value="3">Test2</option>
<option value="4">Test3</option>
</select>
In the angularjs controller, everytime i click on an item in the dropdownlist, i call this function to remove the selected item from the dropdown control:
function removeItemFromDropDown(e) {
var index = e.item.index();
var selectedItem = $scope.dropdownlistCatalogs.dataItem(e.item.index());
$scope.optionsDropDownListCatalogs.dataSource.remove(selectedItem);
}
Now, i want set the selected option to non existing item to show an empty value.
I have tried with:
$scope.dropdownlistCatalogs.value(-1);
but not working
How can i set the dropdownlist by value()?
I'm not sure much about angularjs and if things are different. I see $scope in there which I guess is of angular, since i dont see it defined anywhere. But Usually value will help you with this if using jquery
Add a default blank value at the top with id:-1 and set the default value as 1.
On click of a button, you can change the value to -1
It would look like this :
var data = [
{ "text": "" , id: -1 },
{ "text": "aaa",id: 1 },
{ "text": "bbb",id: 2 },
{ "text": "ccc", id:3}
];
$("#ddl").kendoDropDownList({
dataTextField: "text",
dataValueField: "id",
dataSource: data,
index: 3
});
$("#button").on("click", function ()  {
var dropdownlist = $("#ddl").data("kendoDropDownList");
dropdownlist.value(-1);
});
Here is an working example

AngularJS checkbox filter

I would like to filter the results.
There is a list of wines, my wish is when no checkbox is checked, the entire list of wine is displayed.
when only 1 checkbox is checked is displayed the related category
when more than one checkbox are checked the related categories are displayed
I'm a newbie to AngularJS, I tried with ng-model wihout success, here is the code without ng-model associated to the function:
<html ng-app="exampleApp">
<head>
<title></title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.0-beta.10/angular.min.js"></script>
<script>
angular.module("exampleApp", [])
.controller("defaultCtrl", function ($scope) {
$scope.wines = [
{ name: "Wine A", category: "red" },
{ name: "Wine B", category: "red" },
{ name: "wine C", category: "white" },
{ name: "Wine D", category: "red" },
{ name: "Wine E", category: "red" },
{ name: "wine F", category: "white" },
{ name: "wine G", category: "champagne"},
{ name: "wine H", category: "champagne" }
];
$scope.selectItems = function (item) {
return item.category == "red";
};
$scope.selectItems = function (item) {
return item.category == "white";
};
$scope.selectItems = function (item) {
return item.category == "champagne";
};
});
</script>
</head>
<body ng-controller="defaultCtrl">
<h4>red: <input type="checkbox"></h4>
<h4>white: <input type="checkbox"></h4>
<h4>champagne: <input type="checkbox"></h4>
<div ng-repeat="w in wines | filter:selectItems">
{{w.name}}
{{w.category}}
</div>
</body>
</html>
How to use ng-model or ng-change to associate a function to each checkbox button to have a real time filtering model??
There are several implementations possible. Here's one:
Have a $scope.filter = {} object to hold the state of each filter. E.g. {red: true, white: false...}.
Associate each checkbox with the corresponding property using ng-model. E.g.: input type="checkbox" ng-model="filter['red']" />.
Have a function (e.g. $scope.filterByCategory(wine)) that decides if a wine should be displayed or not (based on the $scope.filter object).
Use that function to filter the items based on their category. E.g. <div ng-repeat="wine in wines | filter:filterByCategory">
The filterByCategory function could be implemented like this:
function filterByCategory(wine) {
// Display the wine if
var displayWine =
// the wine's category checkbox is checked (`filter[category]` is true)
$scope.filter[wine.category] || // or
// no checkbox is checked (all `filter[...]` are false)
noFilter($scope.filter);
return displayWine;
};
where noFilter() is a function that checks if there is any filter activated (and returns true if there is none):
function noFilter(filterObj) {
return Object.
keys(filterObj).
every(function (key) { return !filterObj[key]; });
}
See, also, this short demo.
UPDATE:
I created a modified version, which supports multiple filters (not just filtering by category).
Basically, it dynamically detects the available properties (based on the first wine element), adds controls (groups of check-boxes) for applying filters based on each property and features a custom filter function that:
Filters each wine item, based on every property.
If a property has no filter applied (i.e. no check-box checked), it is ignored.
If a property has check-boxes checked, it is used for filtering out wine items (see above).
There is code for applying multiple filters using AND (i.e. all properties must match) or OR (at least one property must match).
See, also, this updated demo.
Just to add onto #gkalpak answer, I found this codepen which allows you to provide the total amount left after an option is selected for each category.
Change the ng-repeat from:
<div ng-repeat="wine in (ctrl.wines | filter:ctrl.filterByProperties) as filteredWines">
{{ wine.name }} <i>({{ wine.category }})</i>
</div>
To
<div ng-repeat="wine in filtered = (ctrl.wines | filter:ctrl.filterByProperties) as filteredWines">
{{ wine.name }} <i>({{ wine.category }})</i>
</div>
And with the input labels add:
<label>
<input type="checkbox" ng-model="ctrl.filter[prop][value]" />
{{ value }}({{(filtered | filter:value:true).length}})
</label>
I prefer use filter as $filter
app.filter('someFilter',checkboxFilter)
checkboxFilter() {
return function (arr,filter,key,noOne=false) {
// arr is an array of objects
// filter is checkbox filter. someting like {1:true,2:false}
// key is a property in ech object inside arr
// noOne is a behavior if none of checkbox is activated (default:false)
if (!arr.length) return null;
function noOneCheck(filter) {
return Object.keys(filter).every((key) => {
return !filter[key]
})
}
return arr.filter((i) => {
return filter[i[key]] || (noOne && noOneCheck(filter))
})
}
};
html:
ng-repeat="u in project.projectTeamInvite | checkbox:project.status:'status' track by $index">

AngularJS: Binding boolean value to radio button such that it updates model to false on uncheck event

In my AngularJS application, I am displaying contacts data in a grid. My typical contacts JSON looks like as below ...
[
{ type: "IM", value: "mavaze123", default: true },
{ type: "IM", value: "mvaze2014", default: false },
{ type: "IM", value: "mavaze923", default: false },
{ type: "IM", value: "mvaze8927", default: false },
{ type: "Email", value: "mavaze123#abc.com", default: true },
{ type: "Email", value: "mvaze2014#xyz.net", default: false }
]
The last property 'default' is actually a radio button, selection of which should alter the original default value of the corresponding contact type in above JSON. There can be one default from each type of contact i.e. we can group radio buttons based on the contact type.
<div ng-repeat="contact in contacts">
<div>{{contact.type}}</div>
<div>{{contact.value}}</div>
<div><input type="radio" name="{{contact.type}}" ng-model="contact.default" ng-value="true"/></div>
</div>
Note: The above code is not the exact one, but approximately same, as
it will appear inside a custom grid component.
Now when I load my view/edit form page with above JSON, it correctly shows the radio state of all contacts. The problem comes, after page load, when user selects another contact as default. This actually changes the model value of default to true for newly selected contact however the model value of original default contact still remains true, even though its radio state changes to uncheck/blur (because they are having same 'name' value).
I thought to write a directive, but I am unable get it triggered on radio on-blur/uncheck event.
There are various posts on binding boolean values to radio buttons, but I am unable to get it work in my scenario, as I want to update model values for individual radio button in a radio group. See there is no single model representing a radio group.
I think you should change your design to separate the contacts from contactTypes and store the key to the default contact in contact type.
In your current design, there are duplicated values for default and that's not the desired way to work with radio.
$scope.contacts = [
{ type: "IM", value: "mavaze123" },
{ type: "IM", value: "mvaze2014" },
{ type: "IM", value: "mavaze923" },
{ type: "IM", value: "mvaze8927" },
{ type: "Email", value: "mavaze123#abc.com" },
{ type: "Email", value: "mvaze2014#xyz.net" }
];
$scope.contactTypes = {
"IM": { default:"mavaze123"}, //the default is contact with value = mavaze123
"Email": { default:"mavaze123#abc.com"}
};
You Html:
<div ng-repeat="contact in contacts">
<div>{{contact.type}}</div>
<div>{{contact.value}}</div>
<div><input type="radio" name="{{contact.type}}" ng-model="contactTypes[contact.type].default" ng-value="contact.value"/></div>
</div>
DEMO
I assume that the key of contact is value, you could use an Id for your contact.
I added an attribute directive in my input statement ...
<div ng-repeat="contact in contacts">
<div>{{contact.type}}</div>
<div>{{contact.value}}</div>
<div><input type="radio" name="{{contact.type}}" ng-model="contact.default" ng-value="true" boolean-grid-model /></div>
</div>
And my custom directive ...
myModule.directive('booleanGridModel') {
return {
restrict: 'A',
require: 'ngModel',
link: function (scope, elem, attrs, controller) {
var radioSelected = scope.$eval(attrs.ngModel);
if(radioSelected) {
var selectedContact = scope.contact;
_.each(scope.contacts, function(contact) {
if(contact.type === selectedContact.type) {
_.isEqual(contact, selectedContact) ? contact.default = true : contact.default = false;
}
});
}
}
};
}
WHy you declare ng-value="true" please remove that
<div><input type="radio" name="{{contact.type}}" ng-model="contact.default" ng-value="{{contact.default}}"/></div>
Please use $scope.$apply() in your value changing code
Like something below
$scope.$apply(function ChangeType()
{
/Code
});
And you need to change name="{{contact.type}}" to name="contact.type{{$index}}" Because some types are same name.

Resources