Some trouble with saving some array that uses a main-array, but is added to another object.
I have a list of distances (array of numbers).
<ul>
<li v-for="(distance, index) in distances">
<a>{{ distance }} km</a>
</li>
</ul>
And the same view I can add some new distances
<input type="number" v-model="newDistance" /><button #click="addDistance(newDistance)">+</button>
This works, the distances are added to the array when added.
After adding the distance to the ul-list, I also want to add the distances to the checkboxes of each Car that is inside an other array.
<article v-for="car in cars">
<div v-for="(distance, index) in distances">
<div #click="updateCar(car, product.distances)">
<input :id="car.slug+index" :name="car.slug" type="checkbox" :checked="checkDistances(surface, car)" />
<label :for="car.slug+index">{{ distance }} km</label>
</div>
</div>
</article>
The working Functions:
checkDistances(distance, car) {
var self = this;
if(typeof car.distances === 'object') {
if(typeof car.distances[self.form.slug] !== 'undefined') {
return (car.distances[self.form.slug].includes(distance))
}
}
return false;
},
And the function to add distances:
addDistance(newDistance) {
this.distances.push(parseInt(newDistance));
},
This is the UpdateCar function
updateCar(car, distances) {
console.log(this.distances);
console.log(distances);
},
Both console logs show the same array. It all returns always ALL items the are in the 'distances' array and not only the selected input fields..
What I want, is that I can update a car when checking a checkbox, so it'll return only the distances that are selected.
It seems like you're just toggling the checkboxes on and off based on the result of checkDistances, but not storing them anywhere. The organization of your example isn't 100% clear to me, but you probably want something along these lines:
// In your template
<input
:id="car.slug+index"
:name="car.slug"
type="checkbox"
:checked="distance in car.distances"
#click="addDistanceToCar(distance, car)" />
// In your methods:
addDistanceToCar(distance, car) {
car.distances.push(distance)
}
Related
My project is trying to do a dropdown filter and when I select a certain item like soccer in the dropdown it doesn't come up showing that athlete in the specific item selected. Below is the code for my javascript filtering and [my image is supposed to show the soccer player since that was the filter selected][1]. and my HTML is below also for how it is displayed
//returns the value of selected value and filters the athleteList by the selected dropdown and value
filterObj.selectedValue = function(anchorObj) {
console.log("Selected Value: " + anchorObj.id);
//This is used to set the initial value of valueLabel
//If (anchorObj.id === undefined) is true the operator returns the value of the first expression
//If it's false it returns the value of the second expression
valueLabel = (anchorObj.id === undefined) ? "" : (": " + anchorObj.id);
//Calls the filterLabel function and sets it's parameters to the user selected dropdown and filter value
filterLabel(dropdownLabel, valueLabel);
//The switch takes the activeFilter as a parameter which was assigned a value in the selectedDropDown function
//The if statement parameters check if the user selected "All-Sports" if thats the value the user
//selected filterFn remains null since those options are made to display everything
//The function will only return true when the object in the array has a key/value pair that matches the filter
//For example if we select the Sport and then Soccer, Sport is key and Soccer is our value so the object
//has a Sport key equal to Soccer it will return true
var filterFn = null;
switch (activeFilter) {
case "Sport":
if (anchorObj.id === "All-Sports") {
filterFn = null;
break
}
filterFn = function (c) {
return anchorObj.id === c.sport;
};
}
//The switch statement returns two possible types of values. It's either set to null or to the value of a function that returns/sets a value of true
//or false for every elements in the array
//The ternary operator is used to set the value of filteredAthletes
//If filterFn is not null is true the first statment executes, otherwise the second statement executes
//The first statement takes the athletesList, which is the object list, applies the filter method to it with the parameter filterFn
//The second statement returns the unfiltered athleteList
//The filter method takes every object in filterFn that returned true and those are the only objects stored in the filterAthletes array
var filteredAthletes = filterFn ? athleteList.filter(filterFn) : athleteList;
console.log(filteredAthletes);
//The final step is to display the filteredAthletes
//We do this by setting the innerHTML value of our div with id listHere to ${filteredAthletes.map(athleteTemplate).join("") which
//returns a new array (maps) with the specific elements referenced in the athleteTemplate function and joins them to a string seperated by a space
document.getElementById("listHere").innerHTML = `
${filteredAthletes.map(athleteTemplate).join("")}
`;
};
//Called to display unfiltered list
filterObj.selectedValue({});
//Athlete template (keep in this file because its referenced by the function above) pulic method
//This is a basic template for displaying array of objects on your HTML page
//This can be manipulated and changed to fit the requirements/parameters of your array of objects
//This template requires two things to be displayed, a div in the HTML code and a to be added to the document using the div's id
//The code snippet that adds this template to its designated div on the HTML page is in the function below
//<div class="column"><div class = "content"><a href="${athlete.url}" target="_blank">
function athleteTemplate(athlete) {
return `
<div class = "content">
<img src="${athlete.image}">
<div class="overlay">
<div class="text">
<h3>${athlete.athleteName}</h3>
Born: ${athlete.birthday} <br><br>
Age: ${athlete.age} <br><br>
Sport: ${athlete.sport} <br><br>
Learn More
</div>
</div>
</div>
`;
}```
//html
<body>
<div class ="dropContainer">
<div class="dropdown">
<button title="Sport" onclick="filter.myFunction(); filter.selectedDropDown()" class="dropbtn">Sports</button>
<div id="Sport" class="dropdown-content">
<input type="text" placeholder="Search..." id="myInput2" onkeyup="filter.filterFunction('myInput2')">
<a id="All-Sports" onclick="filter.selectedValue(this)" href="#all">Show All</a>
<a id="Soccer" onclick="filter.selectedValue(this)" href="#Soccer">Soccer</a>
<a id="Basketball" onclick="filter.selectedValue(this)" href="#Basketball">Basketball</a>
<a id="Football" onclick="filter.selectedValue(this)" href="#Football">Football</a>
<a id="Baseball" onclick="filter.selectedValue(this)" href="#Baseball">Baseball</a>
<a id="Golf" onclick="filter.selectedValue(this)" href="#Golf">Golf</a>
<a id="Tennis" onclick="filter.selectedValue(this)" href="#Tennis">Tennis</a>
</div>
</div>
</div>
<center>
<div class="header">
<h1>Dropdown Filter with Image Overlay</h1>
<h2>Select the 'Sports' menu and select an option to filter the list by. <br>
Use the Search Bar to filter the dropdown. <br>
Hover over the images for more information on the athlete. <br>
Click 'Learn More' to go to their Wiki page.</h2>
<h2>Current Filter:</h2>
<div class="filter" id='filteredBy'></div>
</div>
<div class="wrapper" id="listHere"></div>
</center>
<script src="js/athletes.js"></script>
<script src="js/MakeFilter.js"></script>
<script>
var athleteList = getAthleteList();
var filter = MakeFilter("Sport", "Filter", "myInput2", athleteList);
</script>
</body>
[1]: https://i.stack.imgur.com/YIHKA.jpg
I am trying to write an end to end test using protractor and i want get the names from a list to check which check boxes have been selected which one's are not.
I can check using isSelected() to check the state of the checkbox but how do i get the list of the names corresponding to it.
This is what i have i want get the label Option 1 and option 2 one by one to see if it is selected or not:
<ul _ngcontent-c8="" class="children" style="">
<li _ngcontent-c8="" class="ng-tns-c8 " ng-reflect-ng-class="[object Object]">
<input _ngcontent-c8="" class="ng-tns-c8" id="all" type="checkbox">
<label _ngcontent-c8="" class="ng-tns-c8" for="all">Option 1</label>
</li>
<li _ngcontent-c8="" class="ng-tns-c8 " ng-reflect-ng-class="[object Object]">
<input _ngcontent-c8="" class="ng-tns-c8" id="all" type="checkbox">
<label _ngcontent-c8="" class="ng-tns-c8" for="all">Option 2</label>
</li>
</ul>
Any help and suggestion will be really appreciated
I have two approaches you can try but have not actually ran either of them myself. They both involve getting all list items in that ul first and both are written using the async/await syntax.
option1
let checkedNames = [];
//iterate over all list items
await element.all(by.xpath('ul[#class="children"]//li')).each(async (li) => {
//if checkbox is selected then get label text and add to array
let chkboxIsSelected = await li.element(by.tagName('input')).isSelected();
if (chkboxIsSelected) {
let lableTxt = await li.element(by.tagName('label')).getText();
//Add lable text to array of labels
checkedNames.push(lableTxt);
};
})
Explanation
element.all(by.xpath('ul[#class="children"]//li')) will return an elementFinder array and there are several methods we can call on element finder arrays, all of them listed here. .each is one of those methods and what it will do is iterate over the element finder array and run a function on each element. It needs to have the element passed into the function in order to run.
The syntax for this would be as follows
eleArray.each(function(elementInArray){
})
We can declare this function using arrow notation and as it is an array of list items we are iterating over we can rename the parameter being passed into the function as 'li' to be more descriptive.
eleArray.each((li) => {
})
Also, as I am using the async/await syntax instead of the promise manager I add the keyword async before all of functions that contain an asynchronous opertation, in your case checking if checkbox is selected in browser and getting text from input field.
option2
let allListItems = await element.all(by.xpath('ul[#class="children"]//li'));
//filter out all of the list items that contain unchecked checkboxes
let itemsWithSelectedChkbox = await allListItems.filter(async li => {
return await li.element(by.tagName('input')).isSelected();
});
//convert the array of list items into an array which contains
let textForAllCheckedBoxes = await itemsWithSelectedChkbox .map(async li => {
return await li.element(by.tagName('label')).getText();
})
console.log(`The test associated with all the checked checkboxes is ${textForAllCheckedBoxes}`);
Hope these are of some use to you but let me know if there issues!
I have a miller column constructed in Angular and Bootstrap.
http://codepen.io/smlombardi/pen/WGwGbY
In the second column, clicking the word (link) opens the third column, but I need to have the checkbox add that word to an array of search terms.
If the checkbox is UN-checked, I need to remove that word from the array of search terms. As you can see in the pen, I have the adding part working, but un-checking the box adds the word again.
I realize what I need to do is somehow check the state of the checkbox and if it's true add the word and if it's false check the array for the word (string) and pop it out of the array.
I can't figure out how to check only the checkbox that was clicked.
<div class="col-xs-3 inner-column">
<div class="panel panel-default">
<div class="list-group">
<div class="list-group-item" ng-class="{active: $index === pmt.millercolumn.level1Selected }" ng-repeat="level1 in pmt.millercolumn.level1 track by $index">
<input type="checkbox" ng-model="activeSearchTerm" ng-change="pmt.change($index)" id="ng-change-example1" />
<a href="" ng-click="pmt.getSublevel2($index)" >
{{level1.name}}
<i class="pull-right fa fa-angle-right fa-lg"></i>
</a>
</div>
</div>
</div>
the ng-change on the checkbox calls:
_this.change = function (index) {
var searchTerm = _this.millercolumn.level1[index].name;
_this.searchTerms.push(searchTerm);
};
It looks like you're thinking in a jquery mindset where you need to handle events when something changes. An easier way would be to make each checkbox correspond to an item in the array, so the ng-model would be something like level1.isSelected. Then, to construct your search terms array, use scope.$watch and pass true as the 3rd argument to deep watch your array of items. When a checkbox is checked, your watch will be called and you can reconstruct the search terms array by plucking the terms of the list items that are selected.
Add this code in place of your _change function it works for sure
_this.change = function (index) {
console.log('Clicked on', _this.millercolumn.level1[index].name);
var searchTerm = _this.millercolumn.level1[index].name;
var searchIndex = _this.searchTerms.indexOf(searchTerm);
if (searchIndex == -1) { // If new push
_this.searchTerms.push(searchTerm);
}
else { // Else remove item
_this.searchTerms.splice(searchIndex, 1);
}
console.log(_this.searchTerms);
};
Working codepen demo : http://codepen.io/krishcdbry/pen/EgKgBv
You're running the same code no matter if the checkbox is checked or not. Try something like this:
_this.change = function (index, checked) {
var searchTerm = _this.millercolumn.level1[index].name;
if(checked){
_this.searchTerms.push(searchTerm);
}
if(!checked){
_this.searchTerms.splice(searchTerm);
}
};
FWIW, this is what I did, which works:
<input type="checkbox" ng-model="level1.isSelected" ng-change="pmt.change($index, level1)" id="mycb" />
_this.change = function (index, item) {
if (item.isSelected) {
_this.searchTerms.push(item.name);
} else {
var termToRemove = item.name;
for (var i = _this.searchTerms.length - 1; i >= 0; i--) {
if (_this.searchTerms[i] === termToRemove) {
_this.searchTerms.splice(i, 1);
}
}
}
};
What would be the best way to create a multidimensional associative array from form inputs?
The form looks like this:
<div id="items">
<h4>Engraving Text</h4>
<div class="item" data-position="1">
<h4 id="engraving-item">Item 1</h4>
<label>Engraving Line 1: </label>
<input type="text" class="engraving-input engraving-line1" name="trophy" id="item1-line1">
<br />
<label>Engraving Line 2: </label>
<input type="text" class="engraving-input engraving-line2" name="trophy" id="item1-line2">
<br />
<label>Engraving Line 3: </label>
<input type="text" class="engraving-input engraving-line3" name="trophy" id="item1-line3">
<br />
</div>
</div>
If the user enters that they want multiple items - additional inputs are dynamically added to the form using these first 3 as a template.
I'm looking to create this sort of array (for example if the user added 2 items):
var myArray = {
item1 :
[
{
engraving-line1 : "user entered data",
engraving-line2 : "more user data",
engraving-line3 : "yep, more data"
}
],
item2 :
[
{
engraving-line1 : "user entered data",
engraving-line2 : "more user data",
engraving-line3 : "yep, more data"
}
]
};
I had written this but I think I am headed in the wrong direction with it or at the very least - writing it poorly.
var totalItems = $("#quantity_wanted").val();
jsonObj = [];
i=1;
while (i < totalItems){
items = {};
$('.item[data-position="'+i+'"] :input').each(function(){
var name = $(this).attr("name");
var engraving = $(this).val();
item = {}
item ["name"] = name;
item ["engraving"] = engraving;
items.push(item);
});
jsonObj.push(items)
i++;
}
Just looking for help writing the javascript that will help me to iterate through the inputs on the screen and push them into a multidimentional associative array like the one I listed.
Your code could be much simplified.
data-position attribute in jquery selector doesn't make sense
since you don't actually use its value. You just need to select all
input group containers by their shared class (.item), then, for
each container, select all descendant inputs.
Your code building item element is redundant. You can use inline
object literal/initializer ({...}) instead.
Furthermore, as #Andy noted, items array should be initialized by array literal ([]), not object ({}).
So the code should look like this:
var jsonObj = [];
$('div.item').each(function(){
var items = [];
$(this).find('input').each(function() {
items.push({
name: $(this).attr("name"), engraving: $(this).val()
});
});
jsonObj.push(items)
});
I have a list of checkboxes in my html page, like so:
<ul id="myList">
<li class="checkboxItem">
<input type="checkbox" name="item1" value="001" id="item-1"/>
<label for="item-1" class="checkboxLabel">Display 1</label>
</li>
<li class="checkboxItem">
<input type="checkbox" name="item2" value="042" id="item-2"/>
<label for="item-2" class="checkboxLabel">Display 42</label>
</li>
</ul>
now I make a call to get some json data, which comes back like so:
[{"name":"002","title":"Display 1"}]
what I want to do is loop the returned json and update the list of checkboxes such that any item not in the returned list is disabled, and those where the title matches a given label, the input value is updated.
so in this example, item2 will be disables and item1 will have its value updates to 002.
here's what I have so far, i'm not quite sure where to go from here, that is, what to do inside the loop. I do have some control over how the json is returned, so if it makes sense to retunr the json in another format, I can do that.
EDIT, updated the function, see below. however, once I get inside the for loop inside the each function, elem is getting a value of "0" rather than a js object such as:
{"name":"002","title":"Display 1"}. clearly data, is being transferred from the outside scope of the function to the inside scope of the each function, but how do I make that happen?
function(data) {
$('#myList').children('li').each(function(i,e) {
for(var elem in data) {
var elemDescr = elem['title'];
var elemName = elem['name'];
if(elemDescr==$(this).find('.checkboxLabel').text()) {
$(this).find('input').attr('value',elemName);
}
}
});
It might be easier to have an outer loop for each checkbox, and an inner loop go through each json element, enabling or disabling based on whether the element/checkboxes have a match.
So an inversion of what you have:
function(data) {
$('#myList').children('li').each(function() {
// loop through your data elements here
});
}
Another option (probably less desirable because it may cause multiple disabled/enabled transitions) is to disable all checkboxes, and enable them as you loop through each element.
I have found my problem. rather than doing:
for(var elem in data) {
var elemDescr = elem['title'];
var elemName = elem['name'];
}
I needed to do:
for(var index in data) {
var elemDescr = data[index].title;
var elemName = data[index].name;
}