I'm attempting to extract the ID of checkbox when it is selected, but I can't seem to find a way that fits what I'm trying to do.
First I have the HTML / Angular for the check boxes. The check boxes are generated by three tiers. First there's a service level, then the day of the week and then the service itself (which are what the check boxes are). The service level makes an accordion, the days of the week are loaded into tabs and the check boxes themselves come in as normal.
<div class="delivery-rules">
<div class="panel-group" id="accordion">
<div class="panel panel-default" ng-repeat="level in settings.serviceLevels">
<div class="panel-heading">
<h4 class="panel-title">
<a data-toggle="collapse" data-parent="#accordion" href="#{{level.LevelTmsCode}}">{{level.LevelName}}</a>
</h4>
</div>
<div id="{{level.LevelTmsCode}}" class="panel-collapse collapse in">
<div class="panel-body">
<ul class="nav nav-tabs">
<li id="{{day.Day}}-{{level.LevelTmsCode}}-tab" ng-repeat="day in settings.serviceDays">
<a id="{{day.Day}}-{{level.LevelTmsCode}}" href="#tabContent-{{day.Day}}-{{level.LevelTmsCode}}" ng-click="settings.changeTab(day, level, $event)">{{day.Day}}</a>
</li>
</ul>
<div class="tabContent" id="tabContent-{{day.Day}}-{{level.LevelTmsCode}}" ng-repeat="day in settings.serviceDays">
<h4>{{day.Day}}</h4>
<div class="time-check" ng-repeat="service in settings.services">
<input type="checkbox" value="None" ng-change="settings.showChecked(settings.rules, $event)" ng-model="settings.selected[$index]" class="time-check-input" id="{{level.LevelTmsCode}}-{{day.Day}}-{{service.TimeValidation}}" name="check"/>
<label for="{{level.LevelTmsCode}}-{{day.Day}}-{{service.TimeValidation}}" class="time-check-input"></label> <span>{{service.TimeValidation}}</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
The arrays that build those check boxes, tabs and accordion are loaded with data from a standard http post request. Then once that is complete I place all the possible combinations of all three arrays into one big array and set their checked attribute to false.
// Get Service Levels to Build Delivery Rules Accordion
settings.getDeliveryServices = function() {
$http.get(resourceBase + "api/service/levels").success(function(data) {
settings.serviceLevels = data;
// Get Service Days
$http.get(resourceBase + "api/service/days").success(function(days) {
settings.serviceDays = days;
// Build the Accordion
setTimeout(() => settings.triggerClick(settings.serviceLevels), 500);
$http.get(resourceBase + "api/service/services").success(function (services) {
settings.services = services;
// Build a collection of all possible rules
for (var a = 0; a < settings.serviceLevels.length; a++) {
settings.rulesTmsCode.push(settings.serviceLevels[a].LevelTmsCode + "-");
}
for (var b = 0; b < settings.serviceDays.length; b++) {
settings.rulesDay.push(settings.serviceDays[b].Day + "-");
}
for (var c = 0; c < settings.services.length; c++) {
settings.rulesTime.push(settings.services[c].TimeValidation);
}
var allArrays = [settings.rulesTmsCode, settings.rulesDay, settings.rulesTime];
function allPossibleCases(arr) {
if (arr.length === 1) {
return arr[0];
} else {
var result = [];
var allCasesOfRest = allPossibleCases(arr.slice(1));
for (var i = 0; i < allCasesOfRest.length; i++) {
for (var j = 0; j < arr[0].length; j++) {
result.push(arr[0][j] + allCasesOfRest[i]);
}
}
return result;
}
}
var uncheckedRules = allPossibleCases(allArrays);
for (var i = 0; i < uncheckedRules.length; i++) {
settings.rules.push({
id: uncheckedRules[i],
checked: false
});
}
});
});
});
}
When each box is checked I'm trying to manipulate the combination array so that the selected combination is set to true.
// Check and Filter Rules to send
settings.showChecked = function (object, $event) {
for (var i = 0; i < settings.rules.length; i++) {
if (settings.rules.hasOwnProperty(i)) {
if (typeof settings.rules[i].id == settings.selected[i]) {
settings.showChecked(settings.rules[i], settings.selected[i]);
}
if (settings.rules[i].id === settings.selected[i]) {
settings.rules[i].checked = true;
}
}
}
console.clear();
console.log(settings.rules);
}
Currently, nothing is set to true as I can't seem to be able to get the ID from the checkbox to compare it with the string stored in the ID value of the combination array. So basically I need the ID of the checkbox that was selected and I need to pass that through to the ng-change event.
Try Some thing like this..
<input id={{emp.name}} type=checkbox value="{{emp.name}}" ng-change="settings.showChecked(settings.rules, $event)>
settings.showChecked=function(object,$event)
{
var el = event.target.id
}
the other way is you can pass id value in place event like below
<select id="hairColorComponent" ng-model="hairColor"
ng-options="option.name for option in hairColorData"
ng-change="updateUserData('hairColorComponent')">
$scope.updateUserData = function (id) {
var element = jQuery('#'+id);
};
Related
I have a list whit a dynamically created checkbox inputs and when the list is done and you finish using it, I want to store the checked items from the list to the localstorage.
(I need to store only the checked items when the save button is pressed.)
HTML:
<template id = "index.html">
<ons-page id=tab1>
<div id="listac">LISTA</div>
<ons-list id="products">
<!-- HERE IS WHERE I ADD THE CHECKBOX ITEMS-->
</ons-list>
<ons-speed-dial position="bottom right" direction="left">
<ons-fab>
<ons-icon icon="fa-cog"></ons-icon>
</ons-fab>
<ons-speed-dial-item ONCLICK="savefunction()"> <!--THIS IS THE BUTTON THAT "SAVES".-->
<ons-icon id = "consolidar" icon="fa-cart-arrow-down"></ons-icon>
</ons-speed-dial-item>
<ons-speed-dial-item >
<ons-icon id = "anadir" icon="fa-plus" ></ons-icon>
</ons-speed-dial-item>
</ons-speed-dial>
</ons-page>
</template>
Js:
function add_checkbox_item(){
var product = document.getElementById('addirp').value;
var text_product = document.createTextNode(product);
var checkbox_product = document.createElement('ons-checkbox')
checkbox_product.appendChild(text_product);
var finall_product = document.createElement('ons-list-item');
finall_product.appendChild(checkbox_product);
finall_product.classList.add("products");
document.getElementById('productos').appendChild(finall_product);
dialog = document.getElementById('dialog1');
dialog.hide();
};
function savefunction(){
// HERE IS WHERE I START GETTING LOST
var checkedValue = null;
var inputElements = document.getElementsByClassName('products');
for(var i=0; inputElements[i]; ++i){
if(inputElements[i].checked){
checkedValue = inputElements[i].value;
break;
}
}
}
What you need to do, is to query all the checkbox elements and iterate through them. Your code currently selects the ons-list-item elements instead of the checkboxes.
First, start by making the function select the correct elements:
function savefunction(){
var checkboxes = document.querySelectorAll('.products'); // <-- select the checkboxes
for (var i = 0; i < checkboxes.length; i += 1) { // <-- iterate
if (checkboxes[i].checked) {
// store values
} else { // <-- this branch is optional (I don't know if you need it)
// remove previously stored values
}
}
}
As you can see, I also added an else branch, in case you also want to remove a previously stored value when the user unchecks a previously checked checkbox. However, if you don't need it, just remove the else branch.
From here on, you have two possibilities: You can either store each checked checkbox separately into the localStorage, or you can store a list of all the checked checkboxes.
Each box separately (remember to remove the else branch if you don't need it)
function savefunction(){
var checkboxes = document.querySelectorAll('.products');
for (var i = 0; i < checkboxes.length; i += 1) {
if (checkboxes[i].checked) {
localStorage.setItem(checkbox[i].name, checkbox[i].value); // <-- stores a value
} else {
if (localStorage.getItem(checkbox[i].name)) { // <-- check for existance
localStorage.removeItem(checkbox[i].name); // <-- remove a value
}
}
}
}
A list of all boxes
function savefunction(){
var checkboxes = document.querySelectorAll('.products');
var checked = {};
for (var i = 0; i < checkboxes.length; i += 1) {
if (checkboxes[i].checked) {
checked[checkbox[i].name] = checkbox[i].value;
}
// <-- no need for else, because we simply override
}
localStorage.setItem('checked_boxes', JSON.stringify(checked)); // <-- localStorage can only store `String` values
}
When using the second approach, don't forget to call JSON.parse on the stored values when you want to use them (this is just for demo purposes):
function restoreCheckboxes (checkboxElements) {
var checkboxStates = localStorage.getItem('checked_boxes'),
i;
if (checkboxStates) {
checkboxStates = JSON.parse(checkboxStates); // <-- parse string to object
for (i = 0; i < checkboxElements.length; i += 1) {
if (checkboxStates.hasOwnProperty(checkboxElements[i].name)) {
checkboxElements[i].checked = true;
}
}
}
}
Another point is this: Do you want to persist that information between different sessions or just as long as the current session is active? If the latter is true, consider using sessionStorage instead of localStorage. You can read about their differences on MDN
This code will exactly be working.
Make unique the checkboxes with name parameters.
On-click call function
First function to store the values and second function to restore the values from local storage
function savefunction(){
var checkboxes = document.querySelectorAll('.products');
var checked = {};
for (var i = 0; i < checkboxes.length; i += 1) {
if (checkboxes[i].checked) {
checked[checkboxes[i].name] = checkboxes[i].value;
}
// <-- no need for else, because we simply override
}
localStorage.setItem('checked_boxes', JSON.stringify(checked)); // <-- localStorage can only store `String` values
}
function restoreCheckboxes () {
var checkboxElements = document.querySelectorAll('.products');
var checkboxStates = localStorage.getItem('checked_boxes');
if (checkboxStates) {
checkboxStates = JSON.parse(checkboxStates); // <-- parse string to object
for (i = 0; i < checkboxElements.length; i += 1) {
if (checkboxStates.hasOwnProperty(checkboxElements[i].name)) {
checkboxElements[i].checked = true;
}
}
}
}
<body onload="restoreCheckboxes()">
<div class="box1">
<div class="box2">
iWork for iColud
</div>
<div class="box3">
<input type="checkbox" name="bixby1" onclick="savefunction()" class="products">
</div></div>
<div class="box1">
<div class="box2">
iWork for iColud
</div>
<div class="box3">
<input type="checkbox" name="bixby2" onclick="savefunction()" class="products">
</div></div>
<div class="box1">
<div class="box2">
iWork for iColud
</div>
<div class="box3">
<input type="checkbox" name="bixby3" onclick="savefunction()" class="products">
</div></div>
</body>
I have 1-n <div class="project"> elements which can open their respective table with use of .collapse class. I filter the text content in every table to hide or show its content. Now I count the number of matching elements for every table. I want to display the value of the counter in every respective <span>of the <div> element. Someone may knows how I can do that?
My HTML:
<div class="project">
<div class="project-Content">
<div style="margin-top:10px; margin-bottom:10px; margin-left:10px">
<a data-toggle="collapse" data-target="#vw" style="cursor:pointer;">
<!--I WANT TO DISPLAY IT IN THE () of the span-->
<b>Volkswagen <span>()</span></b>
</a>
</div>
</div>
<div class="collapse" id="vw">
<table class="table table-striped table-hover">
<tr class="carsName">
<td>Golf</td>
</tr>
<tr class="carsName">
<td>Polo</td>
</tr>
<tr class="carsName">
<td>Passat</td>
</tr>
</table>
</div>
</div>
<!-- ...SOME MORE OF <div class="Project">... -->
<input type="text" class="form-control filter" id="testFilter" name="testFilter" placeholder="Search"/>
My JQuery:
//Filter and Count matching elements
$('#testFilter').keyup(function () {
var filter_array = new Array();
var filter = this.value.toLowerCase(); // no need to call jQuery here
filter_array = filter.split(' '); // split the user input at the spaces
var arrayLength = filter_array.length; // Get the length of the filter array
$('.collapse, .in').each(function() {
// counter for visible tr-elements
var nrOfVisibleCars = 0;
$(this).find("tr").each(function() {
var _this = $(this);
var car = _this.find('td').text().toLowerCase();
var hidden = 0; // Set a flag to see if a tr was hidden
// Loop through all the words in the array and hide the tr if found
for (var i=0; i<arrayLength; i++) {
if (car.indexOf(filter_array[i]) < 0) {
_this.hide();
hidden = 1;
}
}
// If the flag hasn't been tripped show the tr
if (hidden == 0) {
_this.show();
//count all visible tr-elements
nrOfVisibleCars++;
}
});
// Show for every closed Collapse (.collapse) or open Collapse (.in) the counter
alert(nrOfVisibleCars);
// HERE I NEED SOME NEW CODE TO SHOW 'nrOfVisibleCars'
// IN <span>()</span> OF EVERY RESPECTIVE <div>
});
});
Thanks in advance for the help.
Please try this
//Filter and Count matching elements
$('#testFilter').keyup(function () {
var filter_array = new Array();
var filter = this.value.toLowerCase(); // no need to call jQuery here
filter_array = filter.split(' '); // split the user input at the spaces
var arrayLength = filter_array.length; // Get the length of the filter array
$('.collapse, .in').each(function() {
// counter for visible tr-elements
var nrOfVisibleCars = 0;
var $parent = $(this).parent();
$(this).find("tr").each(function() {
var _this = $(this);
var car = _this.find('td').text().toLowerCase();
var hidden = 0; // Set a flag to see if a tr was hidden
// Loop through all the words in the array and hide the tr if found
for (var i=0; i<arrayLength; i++) {
if (car.indexOf(filter_array[i]) < 0) {
_this.hide();
hidden = 1;
}
}
// If the flag hasn't been tripped show the tr
if ($(this).is(':hidden')) {
//count all visible tr-elements
nrOfVisibleCars++;
}
});
// HERE I NEED SOME NEW CODE TO SHOW 'nrOfVisibleCars'
$parent.find('span').html($('tr').length - nrOfVisibleCars);
});
});
DEMO
I have some checkboxes inside blocks like this :
<div ng-show="searchIn.IS" class="filterContent">
<div ng-click="toggleFilter('IS')">
<span class="{{filters.IS}}FilterIcon"></span>
Information System :
</div>
<div ng-show="filters.IS">
<md-checkbox ng-repeat="IS in ISList" ng-click="setISSearch(IS)" ng-checked="isInISSearch(IS)">
{IS}}
</md-checkbox>
</div>
</div>
<br />
<div ng-show="searchIn.area" class="filterContent">
<div ng-click="toggleFilter('area')">
<span class="{{filters.area}}FilterIcon"></span>
Area :
</div>
<div ng-show="filters.area">
<md-checkbox ng-repeat="area in filterAreaList" ng-click="setAreaSearch(area)" ng-checked="isInAreaSearch(area)" ng-show="isInCurrentAreas(area)">
{{area}}
</md-checkbox>
</div>
</div>
So the thing is that filterAreaList is changed each time I check or uncheck a checkbox from the ISList block. But the view is not updated, all the area are still displayed.
I also tried ng-if instead of ng-show.
$scope.filterAreaList = [];
$scope.getAreaFilters = function () {
$scope.searchedIS = $scope.ISList.slice();
for (var i = $scope.searchedIS.length; i >= 0; i--) {
if ($scope.searched.IS.indexOf($scope.searchedIS[i]) === -1)
$scope.searchedIS.splice(i, 1);
}
for (var i = 0; i < $scope.areaList.length; i++) {
for (var j = 0; j < $scope.searchedIS.length; j++)
if ($scope.hasArea($scope.searchedIS[j], $scope.areaList[i]))
$scope.filterAreaList.push($scope.areaList[i]);
}
};
$scope.isInCurrentAreas = function (area) {
if ($scope.filterAreaList.indexOf(area) === -1)
return false;
return true;
};
Some other topics pointed to this : http://www.bennadel.com/blog/2443-rendering-dom-elements-with-ngrepeat-in-angularjs.htm
But I don't really see how to apply this to my case.
Well, I actually missed a few things :
In order to make it work, I added : $scope.filterAreaList = []; in my getAreaFilters() function, and I call getAreaFilters() in my setAreaSearch(area)
And that's it.
I have here the following script which is causing me some errors:
var sections = ["#general_info", "#address_records", "#employment_history", "#driver_experience", "#military_experience", "#eeo_survey", "#psp_notice", "#eva"];
for(var i = 0; i < sections.length; i++){
$(sections[i]).find('input, select').each(function(){
$(this).change(function(){
validate();
$(this).closest('.placement').find('.module-heading').removeClass('module-heading-bad');
$(this).closest('.placement').find('.glyphicon').addClass('glyphicon-ok text-success');
$(this).closest('.placement').find('.glyphicon').removeClass('glyphicon-warning-sign text-danger');
$(sections[i]).find('input, select').each(function(){
if($(this).closest('div').hasClass('has-error')){
$(this).closest('.placement').find('.module-heading').addClass('module-heading-bad');
$(this).closest('.placement').find('.glyphicon').addClass('glyphicon-warning-sign text-danger');
$(this).closest('.placement').find('.glyphicon').removeClass('glyphicon-ok text-success');
return false;
}
});
});
});
}
function validate(){
var driving_qs = ['driving_exp_qa', 'driving_exp_qb', 'driving_exp_qc', 'driving_exp_qd'];
for( var i = 0; i < driving_qs.length; i++){
if($('input[name='+driving_qs[i]+']:checked').val()){
$('input[name='+driving_qs[i]+']').closest('.form-group').removeClass('has-error');
$('input[name='+driving_qs[i]+']').closest('.form-group').addClass('has-success');
}else{
$('input[name='+driving_qs[i]+']').closest('.form-group').addClass('has-error');
$('input[name='+driving_qs[i]+']').closest('.form-group').removeClass('has-success');
}
}
var fields = [{
selector: $('.not-empty'),
validations: [ isNotEmpty]
},{
selector: $('.email'),
validations: [ isNotEmpty, isEmail]
},{
selector: $('.number'),
validations: [ isNotEmpty, isNumber]
},{
selector: $('.number-noreq'),
validations: [isNumberNotRequired]
}];
$('.form-control').closest('div').removeClass('has-error');
var i = 0, k = 0, z = 0, j = fields.length, item, selector, fn, info;
for(; i < j; i++){
item = fields[i];
for(k = 0; k < item.validations.length; k++){
fn = item.validations[k];
for( z = 0; z < item.selector.length; z++){
selector = $(item.selector[z]);
info = selector.closest('div');
if(info)
var result = fn(selector.val());
if(result){
info.removeClass("has-error");
info.addClass('has-success');
}else{
info.removeClass('has-success');
info.addClass("has-error")
}
}
}
}
}
The script works perfectly fine if I am running it without the for loop in front of it. Here is a quick step by step of what my code does (note: this is without the for loop):
Locate the section in code and find each input an select field
Assign the change event to each target input and select field
On change find closest span of class placement, and fine the first module heading and perform all the adding and removing of classes, just to refresh the heading to a success heading if no errors exist below.
Find all the inputs and selects and check for errors, if they exists return false, and add the error classes back on everything
This script will work all the way to the end of each section like it is supposed to do. However after I tried to do this with the for loop, it created a success scenario after only one input. Why is this happening, and is it even possible to have this function inside a loop like I am currently doing?
Also below I have included samples of the html mark-up
<!-- this tag serves no purpose other than being a bookmark for scripting -->
<span class='placement'>
<!-- Section 1: General Information -->
<div id='general-heading' class='row module-heading module-heading-bad general' data-toggle='#general_info'>
<div class='form-group'>
<div class='col-md-12'>
<h4 class='text-info '>General Information<div id='general-confirmation' class='glyphicon glyphicon-warning-sign pull-right text-danger'></div></h4>
</div>
</div>
</div>
<div id='general_info' class='app-section'>
<div class='form-group'>
<div class='col-xs-12'>
<div class='form-group row'>
<div class='col-sm-6 col-xs-12'>
<label class='control-label'>First Name<span class='req'> *</span></label><br />
<input type='text' class='form-control not-empty' id='first_name' value="<?=$first_name?>"/>
</div>
<div class='col-sm-6 col-xs-12'>
<label class='control-label'>Middle Name</label><br />
<input type='text' class='form-control' id='middle_name' value="<?=$middle_name?>"/>
</div>
</div>
</div>
</div>
</span>
The problem in this block of code:
for(var i = 0; i < sections.length; i++){
$(sections[i]).find('input, select').each(function(){
$(this).change(function(){
...
$(sections[i]).find('input, select').each(function(){
...
}
});
});
});
}
Is that it uses the variable i, which will have changed when the function() inside change is run.
In your case, the simplest way to fix it would be by using the forEach function instead of a for loop, and not using the index at all:
sections.forEach(function(section){
$(section).find('input, select').each(function(){
$(this).change(function(){
...
$(section).find('input, select').each(function(){
...
}
});
});
});
})
This will ensure that the i you mean is different each time.
I have a controller that is pretty much an exact copy of the demo from AngularJS. I wanted to add a function to grab some items from an array within the items.
The issue I am running into is that the results are not filtering along with the main part of the controller.
Here is the original part of the controller.
function EmployerListCtrl($scope, Employer) {
$scope.employers = Employer.query();
$scope.orderProp = 'age';
$scope.getEmployerCount = function () {
return $scope.employers.length;
};
I added this function.
$scope.getSkillsList = function () {
var employerArray = this.employers;
var skillsArray = new Array();
for (var i = 0; i < employerArray.length; i++) {
if (employerArray[i].software != undefined || employerArray[i].software != null) {
for (var j = 0; j < employerArray[i].software.length; j++) {
skillsArray.push(employerArray[i].software[j]);
}
}
}
return skillsArray;
};
I also tried to use the same $scope as the main part of the controller, however it also shows just the initial results.
$scope.getSkillsList2 = function () {
var employerArray = $scope.employers;
var skillsArray = new Array();
for (var i = 0; i < employerArray.length; i++) {
if (employerArray[i].software != undefined || employerArray[i].software != null) {
for (var j = 0; j < employerArray[i].software.length; j++) {
skillsArray.push(employerArray[i].software[j]);
}
}
}
return skillsArray;
};
Here is the contents of the HTML Page. The ng-model="query" is what I am using to filter the ng-repeat.
<div class="container-fluid">
<p>Set One: {{getSkillsList()}}</p>
<p>Set Two: {{getSkillsList2()}}</p>
<div class="row-fluid">
<div class="span2">
<!--Sidebar content-->
Search: <input ng-model="query">
Sort by:
<select ng-model="orderProp">
<option value="name">Alphabetical</option>
<option value="age">Newest</option>
</select>
<p>Number of employers in list: {{getEmployerCount()}}</p>
</div>
<div class="span10">
<!--Body content-->
<ul class="employers">
<li ng-repeat="employer in employers | filter:query | orderBy:orderProp" class="thumbnail">
<img ng-src="{{employer.imageUrl}}">
{{employer.name}}
<p>{{employer.snippet}}</p>
</li>
</ul>
</div>
</div>
</div>
I think you are hoping to have the skillsArray automatically shrink or grow based on the ng-repeat filter. That won't work. In this line:
<li ng-repeat="employer in employers | filter:query | orderBy:orderProp" ...>
the results of the filter are not seen by the parent scope, but only by the ng-repeat scopes. In other words, the filter does not alter $scope.employers, so your skills functions will continue to operate on the full employers array received from the server.
One way to accomplish what you want is to define your own filter function, then chain it with the query filter one:
angular.module('myApp', []).
filter('skills', function() {
return function(filteredEmployers) {
var skillsArray = [];
... do your filtering here ...
return skillsArray;
}
});
Then in your HTML:
<li ng-repeat="skills in employers | filter:query | skills">
{{skill}}
</li>
See also Creating Angular Filters.