Same function not working on different properties - javascript

I have a function to filter a list in an array. The function works when filtering the 'brands' property, but I can not get it to work to filter the 'material' property.
It is exactly the same and does the exact same thing except for the fact that it filters a different property. I have no idea what could be stopping this, but:
'brands' function WILL run when both are present, and standalone
'material' function WILL NOT run when either both are present or standing alone.
HTML (brands function check boxes)[working]
<div class="filter-content">
<input type="checkbox" ng-click="includeBrand('Brand A')"/>Brand A<br>
<input type="checkbox" ng-click="includeBrand('Brand B')"/>Brand B<br>
<input type="checkbox" ng-click="includeBrand('Brand C')"/>Brand C<br>
</div>
JS (brands function)[working]
$scope.brandIncludes = [];
$scope.includeBrand = function(brand) {
var i = $.inArray(brand, $scope.brandIncludes);
if (i > -1) {
$scope.brandIncludes.splice(i, 1);
} else {
$scope.brandIncludes.push(brand);
}
}
$scope.brandFilter = function(products) {
if ($scope.brandIncludes.length > 0) {
if ($.inArray(products.brand, $scope.brandIncludes) < 0)
return;
}
return products;
}
}
HTML (material function check boxes)[not working]
<div class="filter-content">
<input type="checkbox" ng-click="includeMaterial('dry')"/>Dry Materials<br>
<input type="checkbox" ng-click="includeMaterial('wet')"/>Wet Materials<br>
<input type="checkbox" ng-click="includeMaterial('oil')"/>Oils<br>
</div>
JS (material function)[not working]
$scope.materialIncludes = [];
$scope.includeMaterial = function(material) {
var i = $.inArray(material, $scope.materialIncludes);
if (i > -1) {
$scope.materialIncludes.splice(i, 1);
} else {
$scope.materialIncludes.push(material);
}
}
$scope.materialFilter = function(products) {
if ($scope.materialIncludes.length > 0) {
if ($.inArray(products.material, $scope.materialIncludes) < 0)
return;
}
return products;
}
}
I am still a novice to angular, can I not run the same function? Thanks!

So, I've spent probably 10 hours over the past two days staring at my JS to find an answer. I seemed to have forgotten there is a "filter function" that gets called in order to solve my problem. I pin pointed that the fact of the matter wasn't that my filter wasn't working, but more or less, wasn't being included in my HTML.
Here is what I had to change to get it working:
<div class="product-results">
<div class="info" ng-repeat="p in products | filter:brandFilter | filter:materialFilter">
{{p.name}}
{{p.brand}}
<img
ng-if="products.src"
ng-src="{{products.src}}">
</div>
I had to add "| filter:materialFilter" in my class that was printing the array to screen.

Related

Loop through checkboxes and conditionally disable unchecked

I'm trying to write a basic function in pure JS that simply checks the number of checked checkboxes, and if that number exceeds a certain amount, disables the rest. I can achieve this easily in jQuery, but trying to get it working in pure JS. I have a CodePen set up here and I'm including my working JS below. Thanks for any insight here.
(function() {
var checkboxes = document.querySelectorAll('input[id^="mktoCheckbox"]');
var active = document.querySelectorAll('input[id^="mktoCheckbox"]:checked');
var numActive = active.length;
console.log(numActive);
if (numActive > 1) {
for(var i = 0; i < checkboxes.length; i++){
if (checkboxes[i].checked == true) {
return;
} else {
checkboxes[i].disabled == true;
}
}
}
})();
There are two problems in your code:
You're returning from the if condition, which causes the loop to terminate.
You're not assigning true to disabled attribute, instead you're comparing with ==.
Change the related snippet to the following to make it work:
if (numActive > 1) {
for (var i = 0; i < checkboxes.length; i++) {
if (checkboxes[i].checked != true) {
checkboxes[i].disabled = true;
}
}
}
You can find a working fork of your pen here. Following is a working SO snippet:
(function() {
var checkboxes = document.querySelectorAll('input[id^="mktoCheckbox"]');
var active = document.querySelectorAll('input[id^="mktoCheckbox"]:checked');
var numActive = active.length;
console.log(numActive);
if (numActive > 1) {
for (var i = 0; i < checkboxes.length; i++) {
if (checkboxes[i].checked != true) {
checkboxes[i].disabled = true;
}
}
}
})();
<fieldset>
<legend>Choose some monster features</legend>
<div>
<input type="checkbox" id="mktoCheckbox_1" name="feature" value="scales" checked />
<label for="scales">Scales</label>
</div>
<div>
<input type="checkbox" id="mktoCheckbox_2" name="feature" value="horns" />
<label for="horns">Horns</label>
</div>
<div>
<input type="checkbox" id="mktoCheckbox_3" name="feature" value="claws" />
<label for="claws">Claws</label>
</div>
<div>
<input type="checkbox" id="mktoCheckbox_4" name="feature" value="tails" checked />
<label for="tails">Tails</label>
</div>
</fieldset>
Here's a working pen.
First of all, imo, you should use getAttribute and setAttribute on DOM elements. HTMLInputElement.checked afaik only reflects the checked attribute (and converts it to boolean) for convenience.
With that in mind, you need to now test against strings with the strict comparison operator ===. E.g.
if(checkbox.getAttribute('checked') === 'true') {...}
since using == would evaluate to false
true == 'true' // false
Also, instead of the for loop you can make use the for-of loop on DOM collections. I.e. this works:
const checkboxes = document.querySelectorAll('...');
for(const checkbox of checkboxes) {
...
}
Keep in mind that you use continue and break to control the loop and not return.

JavaScript Checkbox

I am having troubles with a script with JS, I am still learning but I am stuck for a while.
The solution should be,
IF a checkbox is checked and the value is "" <-- the msgbox should say an message that the textbox should be filled with a value, and so for each checked checkbox, if you uncheck the checkbox, it should dissapear.
Code of 2 checkboxes in html page
<label>
bangkirai
<input id="chk_bangkirai" type="checkbox" onchange="enableTextBox()" />
</label>
<input type="text" id="bangkirai" name="bangkirai" disabled onchange="enableTextBox()" />
<label>
beukenhout
<input id="chk_beukenhout" type="checkbox" />
</label>
<input type="text" id="beukenhout" name="beukenhout" disabled/>
and the JavaScript, I made for each checkbox an other function, but I need to combine the error message in the same msgbox.
function enableTextBox() {
divOutput = document.getElementById("msgbox2");
strValideer = "<ul>";
if (document.getElementById("chk_bangkirai").checked === true) {
document.getElementById("bangkirai").disabled = false;
}
else {
document.getElementById("bangkirai").disabled = true;
}
if (document.getElementById("bangkirai").value === "") {
strValideer += "<li><b>bangkirai: </b>verplicht veld</li>";
}
strValideer += "</ul>";
divOutput.innerHTML = strValideer;
}
function enableTextBox2() {
divOutput = document.getElementById("msgbox2");
strValideer = "<ul>";
if (document.getElementById("chk_beukenhout").checked === true) {
document.getElementById("beukenhout").disabled = false;
}
else {
document.getElementById("beukenhout").disabled = true;
}
if (document.getElementById("beukenhout").value === "") {
strValideer += "<li><b>beukenhout: </b>verplicht veld</li>";
}
strValideer += "</ul>";
divOutput.innerHTML = strValideer;
}
I should probably use an array or an for each itteration ... but I can only find examples with forms ...
I will keep looking for a solution myself, but I hope I can get some inspiration here by experienced coders.
Thanks in advance
You could simplify this a lot and make it more... Concise and less dependent on which checkbox you have. We will do this with an external script and no onClick attributes on our HTML. This will enable us to separate our logic code from our design code. I will also use a placeholder instead of value, as it will create issues when people need to start entering a value (aka, you need to only have the text there when theres no value etc...) It just makes it more complicated.
Since we are dealing with numbers ('stuks' or amounts), lets also only allow number values to be inserted. Lastly, I have not bothered to replicate your HTML as I think the simplified example will make it easier to understand. Update I have also added the required and disabled sattributes here, settings your input to required when the checkbox is checked and disabled when not.
Check the below snippet for comments on the steps taken to do this:
// First, let select all fieldsets like this:
var fieldsets = document.querySelectorAll( 'fieldset.checkbox-message' );
// Lets loop through them
for( let i = 0; i < fieldsets.length; i++ ){
// Lets create variables to store our fieldset, checkbox and input for later use.
let fieldset = fieldsets[ i ];
let checkbox = fieldset.querySelector( 'input[type="checkbox"]' );
let input = fieldset.querySelector( 'input[type="number"]' );
// Lets also store the message we put in placeholder
// We will also give it a default value,
// in case you forget to set the placeholder.
let message = input.placeholder || 'Please fill in the amount';
// Now lets define a function that will fill the placeholder
// based on the checked value of the checkbox
// We will be storing it in a variable because of the scope of a `for` block.
// If you would use function setState() it might be defined globally
// So multiply checkboxes would not work.
let setState = function(){
if( checkbox.checked ){
input.placeholder = message;
input.disabled = false;
input.required = true;
} else {
input.placeholder = '';
input.disabled = true;
input.required = false;
}
}
// Now lets listen for changes to the checkbox and call our setState
checkbox.addEventListener( 'change', setState );
// Lrts also call setState once to initialise the correct placeholder
// for our input element to get started. This will remove any placeholders
// if the checkboxes are unchecked.
setState();
}
<fieldset class="checkbox-message">
<label for="bangkirai">Bangkirai</label>
<input type="checkbox" id="bangkirai" />
<input type="number" placeholder="Tell us, how many 'bangkirai'?" />
<span>stuks</span>
</fieldset>
<fieldset class="checkbox-message">
<label for="beukenhout">Beukenhout</label>
<input type="checkbox" id="beukenhout" />
<input type="number" placeholder="How many 'beukenhout'?" />
<span>stuks</span>
</fieldset>
Good luck coding!
#somethinghere's answer is concise but if we modify your answer as it is you could check this
function enableTextBox() {
bangkirai_validation = document.getElementById("bangkirai_validation");
if (document.getElementById("chk_bangkirai").checked === true) {
document.getElementById("bangkirai").disabled = false;
}
else {
document.getElementById("bangkirai").disabled = true;
bangkirai_validation.style.display='none';
return;
}
if (document.getElementById("bangkirai").value =="") {
bangkirai_validation.style.display='block';
}else
{
bangkirai_validation.style.display='none';
}
}
function enableTextBox2() {
beukenhout_validation = document.getElementById("beukenhout_validation");
if (document.getElementById("chk_beukenhout").checked === true) {
document.getElementById("beukenhout").disabled = false;
}
else {
document.getElementById("beukenhout").disabled = true;
beukenhout_validation.style.display='none';
return;
}
if (document.getElementById("beukenhout").value == "") {
beukenhout_validation.style.display='block';
}else
{
beukenhout_validation.style.display='none';
}
}
<fieldset>
<legend>Bestel gegevens</legend>
<div class="container">
<div class="row">
<div class="span7 id=" houtsoorten"">
<div class="control-group">
<label class="control-label">
bangkirai
<input id="chk_bangkirai" type="checkbox"
onchange="enableTextBox()" >
</label>
<div class="controls">
<div class="input-append">
<input class="inpbox input-mini"
type="number" id="bangkirai" name="bangkirai" placeholder="aantal" disabled
onkeyup="enableTextBox()" onchange="enableTextBox()">
<span class="add-on">stuks</span>
<div style="display:none;" id="bangkirai_validation">Please enter a value</div>
</div>
</div>
</div>
<div class="control-group">
<label class="control-label">
beukenhout
<input id="chk_beukenhout" type="checkbox" onchange="enableTextBox2()" >
</label>
<div class="controls">
<div class="input-append">
<input class="inpbox input-mini"
type="number" id="beukenhout" name="beukenhout" placeholder="aantal"
disabled onkeyup="enableTextBox2()" onchange="enableTextBox2()" >
<span class="add-on">stuks</span>
<div style="display:none;" id="beukenhout_validation">Please enter a value</div>
</div>
</div>
</div>

Javascript append and undo problems

I am having a few problems with javascript. I am trying to create a function for when I click a radio button it will run that function. (I got this to work).
My problem is when I click the radio button to order alphabetically it orders but then when i clicked the other radio buttons to change function it is still ordered alphabetically due to "APPEND" my question is how can I get my program to work so when I kill alphabetically ordered it only orders for that and when i click back to something else its ordered how it was originally.
Here is part of my code:
Javascript:
function radiobuttonclicked() {
var allChampions1 = $(".masterychampsforsum > .colzz");
var selectedcheckyesnochest = document.getElementsByName("optioncheckradiomasterychamps");
if (selectedcheckyesnochest[0].checked == true) {
allChampions1.show();
}
else if (selectedcheckyesnochest[1].checked == true) {
var selectedChampions1 = $(".masterychampsforsum > .colzz[data-chest-champion^='yes']");
allChampions1.hide();
selectedChampions1.show();
}
else if (selectedcheckyesnochest[2].checked == true) {
var selectedChampions1 = $(".masterychampsforsum > .colzz[data-ranked-champion^='yes']");
allChampions1.hide();
selectedChampions1.show();
} else if (selectedcheckyesnochest[3].checked == true) {
var alphabeticallyOrderedDivs = $('.colzz').sort(function(a, b) {
return String.prototype.localeCompare.call($(a).data('championalphabeta').toLowerCase(), $(b).data('championalphabeta').toLowerCase());
});
var container = $("#masterychampsforum");
container.detach().empty().append(alphabeticallyOrderedDivs);
$('.summonerLayout-summary').append(container);
}
}
HTML:
<div class="tabItem Content SummonerLayoutContent summonerLayout-summary" data-tab-spinner-height="800" data-tab-is-loaded-already="true">
<div class="SearchChampion" style="margin-top:20px;padding: 10px;border: 1px solid #000;background-color: #111111;">
<form class="SearchChampionForm" onsubmit="return false;" style="position: relative;">
<input name="optioncheckradiomasterychamps" style="margin-left:15px;vertical-align: middle;margin-top: -1px;" type="radio" value="Chest" id="option_all" onclick="radiobuttonclicked();" checked/> <label for="option_all" style="font-size:16px;">ALL</label>
<input name="optioncheckradiomasterychamps" style="margin-left:15px;vertical-align: middle;margin-top: -1px;" type="radio" value="Chest" id="option_chest" onclick="radiobuttonclicked();"/> <label for="option_chest" style="font-size:16px;">CHEST</label>
<input name="optioncheckradiomasterychamps" style="margin-left:15px;vertical-align: middle;margin-top: -1px;" type="radio" value="Ranked" id="option_ranked" onclick="radiobuttonclicked();"/> <label for="option_ranked" style="font-size:16px;">RANKED</label>
<input name="optioncheckradiomasterychamps" style="margin-left:15px;vertical-align: middle;margin-top: -1px;" type="radio" value="Ranked" id="option_alpha" onclick="radiobuttonclicked();"/> <label for="option_alpha" style="font-size:16px;">ALPHABETICAL</label>
</form>
</div>
<div class="masterychampsforsum" id="masterychampsforum">
<div class="colzz" data-champion-name="'.$getLeagueKeyNamelistsidez.'" data-champion-key="'.$getLeagueKeyNamelistsidez.'" data-chest-champion="'.$champchestyes.'" data-ranked-champion="'.$checkchampionidyesnotrue.'" data-championalphabeta="'.$getLeagueKeyNamelistsidez.'">
</div>
</div>
The data in the data-championalphabeta is Names.
Link to what i got currently
Barmar is right, you have to make a copy first and then you can sort against this copy.
When the last case of your if statement is executed, the DOM is updated.
As the function radiobuttonclicked always retrieves the list from the DOM (the line: var allChampions1 = $(".masterychampsforsum > .colzz")), all the next executions of the function are retrieving the previously ordered list and your original order is lost.
Instead try that (not the best code ever but with this context that will do):
var allChampions1
function radiobuttonclicked() {
if(!allChampions1)
allChampions1 = $(".masterychampsforsum > .colzz").clone();
var selectedcheckyesnochest = document.getElementsByName("optioncheckradiomasterychamps");
if (selectedcheckyesnochest[0].checked == true) {
updateContainer(allChampions1);
} else if (selectedcheckyesnochest[1].checked == true) {
var selectedChampions1 = allChampions1.filter("[data-chest-champion^='yes']");
updateContainer(selectedChampions1);
} else if (selectedcheckyesnochest[2].checked == true) {
var selectedChampions1 = allChampions1.filter("[data-ranked-champion^='yes']");
updateContainer(selectedChampions1);
} else if (selectedcheckyesnochest[3].checked == true) {
var alphabeticallyOrderedDivs = allChampions1.clone().sort(function(a, b) {
return String.prototype.localeCompare.call($(a).data('championalphabeta').toLowerCase(), $(b).data('championalphabeta').toLowerCase());
});
updateContainer(alphabeticallyOrderedDivs);
}
}
function updateContainer(newList){
var container = $("#masterychampsforum");
container.detach().empty().append(newList);
$('.summonerLayout-summary').append(container);
}

How to register order of checkboxes in AngularJS?

I currently have a list of checkboxes in my webapp. I want to show the order in which the checkboxes have been checked. So I wrote the code below.
$scope.updateNumbers = function(id, checked, inputs) {
if (checked === true) {
$scope.count += 1;
var span = angular.element('#'+id+'-'+id);
span.html($scope.count);
} else {
if ($scope.count != 0) {
$scope.count -= 1;
}
for (index = 0; index < inputs.length; ++index) {
var input = inputs[index];
var span = angular.element('#'+test.id+'-'+test.id);
if (span.html() > $scope.count || span.html() == $scope.count) {
span.html(span.html()-1);
}
}
var span = angular.element('#'+id+'-'+id);
span.html($scope.count);
}
}
And this HTML
<div class="list-view__body__row" ng-repeat="restaurant in restaurants">
<div class="list-view__body__cell">
<input type="checkbox" id="<% restaurant.id %>" value=""
class="input-field__checkbox--input"
ng-model="restaurant.checked"
ng-change="updateNumbers(restaurant.id, restaurant.checked, restaurants)">
<label for="<% restaurant.id %>"
class="input-field__checkbox--label"
ng-bind-html="restaurant.name|html"></label>
</div>
<div class="list-view__body__cell">
<div class="order__wrapper" ng-show="restaurant.checked">
<span id="<% restaurant.id %>-<% restaurant.id %>">0</span>
</div>
</div>
</div>
In the current implementation, though, sometimes the number will go down to 0 or numbers will appear twice. It's not working correctly, so how can I improve on this code?
With angular you always want your data model to drive the view. Note that the following solution requires no dom manipulation code and angular manages the dom based on the data. It also requires very little code.
All you need for this is an array of the checked restaurants in your data model.
Then the order is determined by the index within this array and the count is the length of the array.
Controller:
// array to store selections
$scope.checkedItems=[];
$scope.updateSelections = function(rest){
if(rest.checked){
// add to array if item is checked
$scope.checkedItems.push(rest)
}else{
// remove from array if not checked
$scope.checkedItems.splice($scope.checkedItems.indexOf(rest),1)
}
}
View:
<div ng-repeat="restaurant in restaurants">
<div>
<input type="checkbox" ng-model="restaurant.checked"
ng-change="updateSelections(restaurant)">
<label ng-bind="restaurant.name"></label>
</div>
<div ng-show="restaurant.checked">
<!-- Use index to display order -->
Order: <span>{{checkedItems.indexOf(restaurant) +1}}</span>
</div>
</div>
<h3>Count of checked items: {{checkedItems.length}}</h3>
DEMO

Two array types into one function

I have a form where you click a button and a collection of elements need the opacity changed and the radio or checkbox selected. I have a bunch of these in the form so I need assistance with creating this type of array. Some of the IDs are dp001, dp002 …. dp050 so there needs to be a condition appending the prefix to it when it gets to dp010. This collection of elements I want to change the opacity. The other collection of elements isn't in any particular order but I want to collect them and make them checked. Somewhere I created a FUBAR :)
Fiddle won't work … really pi$$ing me off don't know why jsfiddle refuses to load javascript for me. Is This Fiddle FUBAR?
On my web server the alert works fine the doesn't do what I want.
Javscript works on my server check it out.
HTML
<div id="dp001">Item #1 <input type="radio" id="abc005"></div>
<div id="dp002">Item #2 <input type="radio" id="abc008"></div>
<div id="dp003">Item #3 <input type="checkbox" id="abc010"></div>
<div id="dp004">Item #4 <input type="checkbox" id="abc020"></div>
<div id="dp005">Item #5</div>
<div id="dp006">Item #6</div>
<div id="dp007">Item #7</div>
<div id="dp008">Item #8</div>
<div id="dp009">Item #9</div>
<div id="dp010">Item #10</div>
<div id="dp011">Item #11</div>
<button type="button" onclick="DoStuff();">Click</button>
JAVASCRIPT
function DoStuff() {
var items = null;
var checkMe = ["abc005" , "abc0008" , "abc010" , "abc020"];
for (i=1 ; i < 12 ; i++) {
if (i < 10) {
items = 'dp00' + i;
} else {
items = 'dp0' + i;
}
}
alert("ding");
document.getElementById("items").style.opacity="0.5";
document.getElementById("checkMe").checked = true;
}
I think you need
function DoStuff() {
var checkMe = ["abc005" , "abc0008" , "abc010" , "abc020"];
for (var i=1; i < 12; i++) {
var items = 'dp0' + (i<10 ? '0' : '') + i;
document.getElementById(items).style.opacity = 0.5;
}
for (var i=0, l=checkMe.length; i<l; ++i)
document.getElementById(checkMe[i]).checked = true;
}
Problems with your code:
"items" is a literal string, not the variable items. Same for "checkMe".
You must change each element inside the loop, not outside.
You don't declare variable i
You can use the ternary conditional to simplify code (optional)

Categories