Limit checkbox selections and bind to an array in AngularJS - javascript

I am trying to achieve two things:
Bind an array to a list of checkboxes (just a string array), and
Limit the number of selections the user can make to a number between
1 and the number of available items less 1.
I can get (2) to work until the user clicks the last item, at which point it loses track and the items remain selected.
The interactive code is up here: http://codepen.io/adamcodegarden/pen/bdbQqe (forked from a similar example)
My HTML/Angular code:
<p ng-repeat="item in allOptions" class="item" id="{{item}}">
{{item}} <input type="checkbox" ng-change="sync(bool, item)" ng-model="bool" ng-checked="isChecked(item)"> Click this to sync this item with the target array. {{item}} Selected: {{bool}}
and the JS:
var myApp = angular.module("myApp", []);
var maxItems = 1;
myApp.controller('myController', function($scope) {
$scope.isChecked = function(item){
var match = false;
for(var i=0 ; i < $scope.data.length; i++) {
if($scope.data[i] === item) {
match = true;
}
}
return match;
};
$scope.allOptions = [
'one', 'two', 'three', 'four'
];
$scope.data = [
];
$scope.sync = function(bool, item){
if (bool) {
// add item
$scope.data.push(item);
// if we have gone over maxItems:
if ($scope.data.length > maxItems) {
//remove oldest item
$scope.data.splice(0,1);
}
} else {
// remove item
for (var i=0 ; i < $scope.data.length; i++) {
if ($scope.data[i] === item){
$scope.data.splice(i,1);
}
}
}
};
});

I like plunker more than codepen. So I created this plunker
http://plnkr.co/edit/l8gxQHXBQdFeKIuwf3f0?p=preview
The main idea is that I format the original array as:
$scope.allOptions = [
{key: 'one'}, {key: 'two'}, {key: 'three'}, {key:'four'}
];
And slight change to the sync logic as well:
$scope.sync = function(bool, item){
if (bool) {
// add item
$scope.data.push(item);
// if we have gone over maxItems:
if ($scope.data.length > maxItems) {
//remove first item
$scope.data[0].checked = false;
$scope.data.splice(0,1);
}
} else {
// remove item
for (var i=0 ; i < $scope.data.length; i++) {
if ($scope.data[i] === item) {
$scope.data.splice(i,1);
}
}
}
};
Also change html portion:
<p ng-repeat="item in allOptions" class="item" id="{{item.key}}">
{{item.key}} <input type="checkbox" ng-change="sync(item.checked, item)" ng-model="item.checked"> Click this to sync this item with the target array. {{item.key}} Selected: {{bool}}

Related

Append text by matching object array's attribute and element id's digit

I have a list of object array with id and value as its properties. Basically what I want is, the num.items[i].value should go in each div as pair. One: one and so on.
If num.items[i].id doesn't have the digit (like the array doesn't include id 3) then the id="digit_3" should be left blank.
HTML
<ul>
<li>One: <div id="digit_1">s</div></li>
<li>Two: <div id="digit_2">sd</div></li>
<li>Three: <div id="digit_3">sdf</div></li>
<li>Four: <div id="digit_4">sdf</div></li>
</ul>
Javascript
var num = {
items: [
{ id:4, value:"four"},
{ id:1, value:"one"},
{ id:2, value:"two"},
]
};
for(var i=0; i<num.items.length; i++){
document.getElementById("digit_"+i+1).innerHTML = i+1;
console.log(i+1)
}
Required output
One: one
Two: two
Three:
Four: four
I know we cannot compare the id digit but any modification in HTML is greatly appreciated.
it's really simple - you just have to understand arrays and objects:
var num = {
items: [{
id: 4,
value: "four"
},
{
id: 1,
value: "one"
},
{
id: 2,
value: "two"
},
]
};
var cleanableElements = document.querySelectorAll("ul li div");
for (var i = 0; i < cleanableElements.length; i++) {
cleanableElements[i].innerHTML = '';
}
var index;
for (var i = 0; i < num.items.length; i++) {
index = num.items[i].id;
document.getElementById("digit_" + index).innerHTML = num.items[i].value;
}
<ul>
<li>One:
<div id="digit_1"></div>
</li>
<li>Two:
<div id="digit_2"></div>
</li>
<li>Three:
<div id="digit_3"></div>
</li>
<li>Four:
<div id="digit_4"></div>
</li>
</ul>
Best idea would be to select all elements with querySelectorAll and setting empty before next step. You can't really detect all #digit_X id's so you can't just check for unchanged DIVs as you can't reliably detect them all.
You should loop ul li div then check id whether is in num.items.
Assuming your id format is digit_*.
var num = {
items: [
{ id:4, value:"four"},
{ id:1, value:"one"},
{ id:2, value:"two"},
]
}
function checkItems(num){
items = document.querySelectorAll('#target_div li div')
indexes = num.items.reduce( (pre, cur) => {
pre[cur.id] = cur.value
return pre
}, {}) // loop num.items then create one dict with key=id.
items.forEach(function(item){ //loop ul li div, then check whether id in dict=indexes.
let ids = item.id.split('_')
if(ids[1] in indexes){
item.innerHTML += ' #Found:'+item.id
} else {
item.innerHTML = ''
}
})
}
checkItems(num)
<ul id="target_div">
<li>One: <div id="digit_1">s</div></li>
<li>Two: <div id="digit_2">sd</div></li>
<li>Three: <div id="digit_3">sdf</div></li>
<li>Four: <div id="digit_4">sdf</div></li>
</ul>
I know I did something awkward but if div have already some value then above example will not work expect #sphinx answer I guess
var num = {
items: [{
id: 4,
value: "four"
},
{
id: 1,
value: "one"
},
{
id: 2,
value: "two"
},
]
};
var idsArray = [];
var valuesArray = [];
for (var value of num.items) {
idsArray.push(value.id);
valuesArray.push(value.value);
}
var maxId = Math.max(...idsArray);
for (var i = 1; i <= maxId; i++) {
if (idsArray.indexOf(i) !== -1) {
document.getElementById("digit_" + i).innerHTML = valuesArray[idsArray.indexOf(i)];
} else {
document.getElementById("digit_" + i).innerHTML = "";
}
}
div {
display: inline
}
<ul>
<li>One: <div id="digit_1">s</div></li>
<li>Two: <div id="digit_2">sd</div></li>
<li>Three: <div id="digit_3">sdf</div></li>
<li>Four: <div id="digit_4">sdf</div></li>
</ul>

Hide Filters with no result of combination | Isotope JS

I am creating an application using Isotope.js with checkbox combination filter. I am managing to get everything working using examples etc..
However I finding an issue how to hide certain filters which will give no results on the filter.
I have created a JSFiddle to demonstrate my example.
Filter options:
<div id="options">
<div class="option-set" data-group="brand">
<input type="checkbox" value="" id="brand-all" class="all" checked /><label for="brand-all">all brands</label>
<input type="checkbox" value=".brand1" id="brand1" /><label for="brand1">brand1</label>
<input type="checkbox" value=".brand2" id="brand2" /><label for="brand2">brand2</label>
</div>
<div class="option-set" data-group="type">
<input type="checkbox" value="" id="type-all" class="all" checked /><label for="type-all">all types</label>
<input type="checkbox" value=".type1" id="type1" /><label for="type1">type1</label>
<input type="checkbox" value=".type2" id="type2" /><label for="type2">type2</label>
</div>
</div>
Items:
<div id="container">
<div class="item brand1 type1 red"></div>
<div class="item brand1 type1 red"></div>
<div class="item brand1 type1 red"></div>
<div class="item brand2 type2 blue"></div>
<div class="item brand2 type2 blue"></div>
<div class="item brand2 type2 blue"></div>
</div>
In my example I have two filters brands & types. If brand 1 is selected as a filter only type 1 of that brand is available so I would like to hide the type 2 checkbox and works vice versa if all is selected.
It should work in a scalable way for any category and not hardcoded categories.
I have tried already achieving this by triggering isotope itself on the filters but didn't work. Also creating events on arrange complete, but still not managing to get the available categories from the filtered items.
Method on arrange items I tried using:
$$container.on( 'arrangeComplete', function( event, filteredItems ) {
filteredItems.forEach(function(elementsData){
console.log($(elementsData.element).attr('class));
});
});
Can someone guide me to the correct solution as I've been hours trying different activations.
Try this:
/*jshint browser:true, undef: true, unused: true, jquery: true */
var $container;
var filters = {};
$(function(){
$container = $('#container');
var $filterDisplay = $('#filter-display');
$container.isotope();
// do stuff when checkbox change
$('#options').on( 'change', function( jQEvent ) {
var $checkbox = $( jQEvent.target );
manageCheckbox( $checkbox );
var comboFilter = getComboFilter( filters );
$container.isotope({ filter: comboFilter });
$filterDisplay.text( comboFilter );
var comboFilters = comboFilter.split(', ');
$(comboFilters).each(function(edx, val) {
var myval = val;
var hidelist = [];
var showlist = [];
$('.option-set input').each(function(edx, ele) {
var selector = $(ele).attr("value") + myval;
if(selector !== "" && $(selector).length === 0)
{
hidelist.push(ele);
//$(ele).hide();
//$("label[for='"+$(ele).attr('id')+"']").hide();
}
else {
showlist.push(ele);
}
});
$(hidelist).each(function(edx, item) {
$(item).hide();
$("label[for='"+$(item).attr('id')+"']").hide();
});
$(showlist).each(function(edx, item) {
$(item).show();
$("label[for='"+$(item).attr('id')+"']").show();
});
});
});
});
function getComboFilter( filters ) {
var i = 0;
var comboFilters = [];
var message = [];
for ( var prop in filters ) {
message.push( filters[ prop ].join(' ') );
var filterGroup = filters[ prop ];
// skip to next filter group if it doesn't have any values
if ( !filterGroup.length ) {
continue;
}
if ( i === 0 ) {
// copy to new array
comboFilters = filterGroup.slice(0);
} else {
var filterSelectors = [];
// copy to fresh array
var groupCombo = comboFilters.slice(0); // [ A, B ]
// merge filter Groups
for (var k=0, len3 = filterGroup.length; k < len3; k++) {
for (var j=0, len2 = groupCombo.length; j < len2; j++) {
filterSelectors.push( groupCombo[j] + filterGroup[k] ); // [ 1, 2 ]
}
}
// apply filter selectors to combo filters for next group
comboFilters = filterSelectors;
}
i++;
}
var comboFilter = comboFilters.join(', ');
return comboFilter;
}
function manageCheckbox( $checkbox ) {
var checkbox = $checkbox[0];
var group = $checkbox.parents('.option-set').attr('data-group');
// create array for filter group, if not there yet
var filterGroup = filters[ group ];
if ( !filterGroup ) {
filterGroup = filters[ group ] = [];
}
var isAll = $checkbox.hasClass('all');
// reset filter group if the all box was checked
if ( isAll ) {
delete filters[ group ];
if ( !checkbox.checked ) {
checkbox.checked = 'checked';
}
}
// index of
var index = $.inArray( checkbox.value, filterGroup );
if ( checkbox.checked ) {
var selector = isAll ? 'input' : 'input.all';
$checkbox.siblings( selector ).removeAttr('checked');
if ( !isAll && index === -1 ) {
// add filter to group
filters[ group ].push( checkbox.value );
}
} else if ( !isAll ) {
// remove filter from group
filters[ group ].splice( index, 1 );
// if unchecked the last box, check the all
if ( !$checkbox.siblings('[checked]').length ) {
$checkbox.siblings('input.all').attr('checked', 'checked');
}
}
}
Fiddler: https://jsfiddle.net/Lsg4zxu7/45/

How to split two items inside a JSON array in angular

This is my code:
$scope.center_name = [];
$scope.stats = ["Stats"];
$scope.totMemCenterData = [];
var query = "SELECT count(*) as tot_mem, centers.name as center_name FROM mem_groups "
+ "INNER JOIN centers ON mem_groups.center_id=centers.id GROUP BY centers.id";
$cordovaSQLite.execute(db, query, [])
.then(function(res){
if (res.rows.length > 0) {
for (var i=0; i < res.rows.length; i++) {
$scope.totMemCenterData = res.rows.item(i);
console.log(JSON.stringify($scope.totMemCenterData));
}
}
}, function(err){
// $cordovaToast.showShortBottom('Something Went Wrong').then(function(success){}, function(err){});
console.log(err.message);
});
This is the result of console.log(JSON.stringify($scope.totMemCenterData)); :
{"center_name":"AFG - ANONANG","tot_mem":6}
{"center_name":"BAM - BUENAVISTA","tot_mem":3}
{"center_name":"GHT - TAGAS","tot_mem":2}
I want to put all center_names in one array also the tot_mem on another array. I want it to be like:
Centers: "AFG - ANONANG", "BAM - BUENAVISTA", "GHT - TAGAS"
Tot_mem: 6, 3, 2
I'm gonna put those values on a chart. Centers on the x-axis and tot_mem on the y-axis
You can do this,
$scope.center_names = [];
$scope.tot_mem = [];
angular.forEach($scope.sampleTest, function(key, value) {
$scope.center_names.push(key["center_name"]);
$scope.tot_mem.push(key["tot_mem"]);
});
DEMO
var app = angular.module('sampleApp', []);
app.controller('myCtrl', function($scope) {
$scope.sampleTest = [{
"center_name": "AFG - ANONANG",
"tot_mem": 6
}, {
"center_name": "BAM - BUENAVISTA",
"tot_mem": 3
}, {
"center_name": "GHT - TAGAS",
"tot_mem": 2
}];
$scope.center_names = [];
$scope.tot_mem = [];
angular.forEach($scope.sampleTest, function(key, value) {
$scope.center_names.push(key["center_name"]);
$scope.tot_mem.push(key["tot_mem"]);
});
});
<!DOCTYPE html>
<html ng-app="sampleApp" xmlns="http://www.w3.org/1999/xhtml">
<head>
<script src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.10/angular.min.js"></script>
</head>
<body ng-controller="myCtrl">
<h1> Center names </h1>
<div ng-repeat="item in center_names">
{{item}}
</div>
<h1> Total memory </h1>
<div ng-repeat="tot in tot_mem">
{{tot}}
</div>
</body>
</html>
Some Observations :
TypeError: res.rows.item is not a function
So, use this res.rows.item[i] instead of res.rows.item(i).
Why JSON.stringify ? As you have to iterate each object to create two different arrays based on the keys. So, leave $scope.totMemCenterData as it is.
Instead of checking the length of res.rows.length check the length of items(res.rows.item.length) as you are going to iterate items.
Working demo :
var myApp = angular.module('myApp',[]);
myApp.controller('MyCtrl',function($scope) {
var res = {
"rows": {
"item": [{
"center_name": "AFG - ANONANG",
"tot_mem": 6
}, {
"center_name": "BAM - BUENAVISTA",
"tot_mem": 3
}, {
"center_name": "GHT - TAGAS",
"tot_mem": 2
}]
}
};
$scope.center_names = [];
$scope.tot_mem = [];
for (var i=0; i < res.rows.item.length; i++) {
$scope.totMemCenterData = res.rows.item[i];
$scope.center_names.push($scope.totMemCenterData.center_name);
$scope.tot_mem.push($scope.totMemCenterData.tot_mem);
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="MyCtrl">
<b>Center Names :</b>
<div ng-repeat="names in center_names">
{{names}}
</div>
<b>Total Mem :</b>
<div ng-repeat="item in tot_mem">
{{item}}
</div>
</div>

every odd letter uppercase in angular js

i am using angular ng-repeat to print a list but i need to make every odd letter of the word in uppercase i am sure there is a scope of it with angular js but dont know how please help.
HTML CODE
<ul ng-app="mySite" ng-controller="MyCtrl">
<li ng-repeat="list in listData">
{{list | myFormat}}
</li>
</ul>
JAVASCRIPT
var app = angular.module('mySite', []);
app.filter('myFormat', function() {
return function(list) {
var i, c, txt = "";
list= list.split("")
for (i = 0; i < list.length; i++) {
c = list[i];
if (i % 2 == 0) {
c = c.toupperCase();
}
txt += c;
}
return txt;
};
});
app.controller('MyCtrl', function($scope) {
$scope.listData = [
'Jani',
'Carl',
'Margareth',
'Hege',
'Joe',
'Gustav',
'Birgit',
'Mary',
'Kai'
];
});
such a silly mistake you are doing
toupperCase(); is wrong use toUpperCase();

How to add object which checked in array?

I have checkboxes in the application, When I click check-box , The object which I checked, is added in array. But When I click one more time checkbox (unchecked), The object is not removed in array.
How can I fix it ?
HTML Source:
<ion-list ng-repeat="option in question.SurveyOptions ">
<li class="item item-checkbox checkbox-royal ">
<label class="checkbox">
<input type="checkbox" ng-checked="MyAnswers.indexOf(option)!=-1" ng-click="toggleCheckAnswer({OptionId:option.Id,QuestionId:question.Id})">
</label>
<div class="item item-text-wrap">
{{option.OptionsName}}
</div>
</li>
</ion-list>
Controller:
$scope.MyAnswers = [];
$scope.toggleCheckAnswer = function(Answer) {
if ($scope.MyAnswers.indexOf(Answer) === -1) {
$scope.MyAnswers.push(Answer);
} else {
$scope.MyAnswers.splice($scope.MyAnswers.indexOf(Answer), 1);
}
};
In the function Answer include only OptionId and QuestionId.
How can I find index of {OptionId:1,QuestionId:1}?
Try like this
var index = $scope.MyAnswers.map(function(x) {
return x.OptionId + "#" + x.QuestionId;
}).indexOf(Answer.OptionId + "#" + Answer.QuestionId);
console.log(index);
You can't use indexOf to find objets in array you need to iterate over array:
$scope.toggleCheckAnswer=function(Answer) {
var index = -1;
for (var i=0; i<$scope.MyAnswers.length; ++i) {
var answer = $scope.MyAnswers[i];
if ($scope.MyAnswers[i].OptionId == Answer.OptionId &&
$scope.MyAnswers[i].QuestionId == Answer.QuestionId) {
index = 1;
break;
}
}
if (index === -1) {
$scope.MyAnswers.push(Answer);
} else {
$scope.MyAnswers.splice(index, 1);
}
};

Categories

Resources