push dynamically coming id's and value's in javascript - javascript

The question may seem a little confusing so let me explain the situation, i have a category field, that when it's chosen, i get data from api based on that category, for example when you choose category A, you may get the id's 1 to 3 or when you chose category B, you get the id's of 8 to 11, so what i'm trying to do is create a Filter array that pushes these values with id's so when user types something like sth in input with the id of 1, this objects gets pushed to the array, something like below:
Filters = [
{
id:1,
value: sth
}
]
so what i have basically done is something like this:
this.props.Filters.map(item => (
<div className="from" key={item.id} id={item.id} >
<span className="title">{item.feature}</span>
<input type="text" placeholder="..." id={item.id} onChange={FilterPush}></input>
</div>
))
and the function is:
const Filters = []
const FilterPush = (e) => {
const filter = {
id: e.currentTarget.getAttribute("id"),
value: e.currentTarget.value
}
Filters.push(filter)
}
the problem i'm having here is every time a user is typing something an object is pushed to Filters,
so when user tries to type sth the Filter gets equal to:
Filters={
{id:1,value:s},
{id:1,value:st},
{id:1,value:sth}
}
but i want it to be equal to this
Filters={
{id:1, value:sth}
}
bear in mind that the id's are dynamic and i don't know them, and there's not just one input, i mean we can have 3 inputs with diffrent id's that should get send to the server.

Just filter out existing id:
const FilterPush = (e) => {
let id = e.currentTarget.getAttribute("id")
const filter = {
id,
value: e.currentTarget.value
}
Filters = Filters.filter(item => item.id !== id) // filter out existing id
Filters.push(filter)
}

It's very simple all you have to do is just check the pushing element's id is already in the Filters array before pushing the element.
const FilterPush = (e) => {
let id = e.currentTarget.getAttribute("id")
const filter = {
id: e.currentTarget.getAttribute("id"),
value: e.currentTarget.value
}
Filters.map(item=>{
if(id == item.id){
available = true;
}
})
if(!available){
Filters.push(filter)
}
}

Related

How can I write a For loop from dropdown box to populate second dropdown box from JSON file?

I have a Jinja for loop populating one dropdown box for countries. This allows a user to select a country. But I have second Jinja for loop populating a second dropdown box for states. At the moment, the second dropdown box just iterates every state in the list (which is 1000s).
So I am building a JavaScript to iterate through the JSON file and collect the data of the user chosen country to populate the state's list with only states that are associated with that particular country.
Unfortunately, this is where I get stuck. I am not too familiar with the common concept of a for loop in JS.
So far I can pick this:
document.getElementById("country").addEventListener("change", function() {
const country_change = document.getElementById("country").value;
console.log(country_change);
console.log(countries);
});
Where country_change is the user-chosen country and countries is the entire JSON file.
Clicking on the countries log first entry I get:
This is what I want to iterate through to:
I can call all the countries from the JSON file into JS, now when a user selects a country I have that variable, so now I want to look through states for that country and its associated states.
I tried a simple for loop from w3 schools just to see what comes out - but there wasn't anything really useful that I could gather. I think I just need a bit more of a shove in the right direction.
Edit: Just experimenting with:
document.getElementById("country").addEventListener("change", function() {
const country_change = document.getElementById("country").value;
console.log(country_change);
console.log(countries);
const Ind = countries.findIndex(e => {
return e['name'] === country_change
})
if(Ind != -1){
countries[Ind]['states'].forEach(e=>console.log(e))
}
});
But still not producing the desired results.
You could do something like this:
Every time the country dropdown value changes, update all state options.
function updateSelect({ node, values }) {
while (node.hasChildNodes()) node.removeChild(node.lastChild)
for (const value of values) {
const option = document.createElement("option")
option.value = option.textContent = value
node.appendChild(option)
}
}
// Sample data
const countries = [
{
name: "Germany",
states: ["Bavaria", "Berlin", "Saxony"]
},
{
name: "Austria",
states: ["Tyrol", "Vienna"]
}
]
const coutriesSelect = document.querySelector("#country")
const statesSelect = document.querySelector("#state")
updateSelect({
node: coutriesSelect,
values: countries.map(country => country.name),
})
// Update it on initialization
updateStatesSelect()
coutriesSelect.addEventListener("change", updateStatesSelect)
function updateStatesSelect() {
const countryName = coutriesSelect.value
const country = countries.find(country => country.name === countryName)
const states = country.states
updateSelect({
node: statesSelect,
values: states
})
}
<select name="country" id="country"></select>
<select name="state" id="state"></select>
It appears this will iterate through that list and produce the states:
const Ind = countries.findIndex(e => {
return e['name'] === country_change
})
if(Ind != -1){
countries[Ind]['states'].forEach(e=>console.log(e))
}
Based on the data I have given.

show result List as per count

Like here, I want the number of times it has in registration array, I want to show it in a single row. Currently its like below, But I want it like if there's 2 result then I want it 2 time in a single row.
So here if you check the prototype(of item), You can see 2 count, so i want to show 2 results, along sides.
const title = responseData.map(item => {
return { label: `${item.title} (${item.registration[0].registration_type.code}) (${item.registration.length.toString()})`, value: item._id };
});
I am assuming the data you want in each row is all stored inside each element in the item.registration array.
const title = responseData.map(item => {
// map all the values inside the registration on to an array of labels
const labels = item.registration.map(registration => {
return `${item.title} (${registration.registration_type.code})`;
})
// Join the labels created above with a comma separating them
return { label: labels.join(', '), value: item._id };
});

Trouble with React/JS filter

I am trying to implement a filter function that is able to search in two separate JSON fields when a user types in a search bar. Searching the whole JSON returns errors and if I repeat this function, the two similar functions cancel each other out.
My current filter function:
let filteredOArt = origArt.filter((origAItem) => {
return origAItem.authors.toLowerCase().includes(this.state.search.toLowerCase())
});
I want to be able to have the search look within the "authors" field as well as a "description" field.
Before the React render, I have this function listening to the state:
updateSearch(event) {
this.setState({ search: event.target.value })
}
Then my search function is in an input field in the React return:
<h6>Search by author name: <input type="text" value={this.state.search} onChange={this.updateSearch.bind(this)} /></h6>
You can tweak the function a bit like this
let filteredOArt = origArt.filter((origAItem) => {
return (
(origAItem.authors.toLowerCase().includes(this.state.search.toLowerCase())||
(origAItem.description.toLowerCase().includes(this.state.search.toLowerCase())
)
)
});
You actually can do a filter for both fields.
Given you have your searchValue and your array with the objects you could filter this way:
const filterByAuthorOrDescription = (searchValue, array) =>
array.filter(
item =>
item.authors.toLowerCase().includes(searchValue.toLowerCase()) ||
item.description.toLowerCase().includes(searchValue.toLowerCase())
);
const filtered = filterByAuthorOrDescription(this.state.search, articles);
filtered will now contain an array of objects that contain your searchValue in either description or authors that you can map through.
You could use some to check if the filter is positive for at least one field :
let filteredOArt = origArt.filter(origAItem => ['authors', 'description'].some(field => origAItem.[field].toLowerCase().includes(this.state.search.toLowerCase())))
Just iterate over the different field names you want to use.
Some will return true if any of the fields mentioned contains your string and avoid repetitions in your code.
Long syntax :
origArt.filter(origAItem => {
return ['authors', 'description'].some(field => origAItem.[field].toLowerCase().includes(this.state.search.toLowerCase()))
})

How to Compare Values from 2 Arrays to Filter Out Elements

I'm having a really difficult time figuring out this problem. I have two arrays (cars and active_filters). The cars array contains html li tags with attributes such as car type, number of seats, price, etc. The active_filters array contains objects related to which filters the user interacted and will be used for which cars to display or hide.
Example: When looking at active filters for id data-type, the value property includes a list of all car codes that the user is wanting to display. If a cars data-type is not found or equal to one of these car codes, my goal is to hide these cars by adding class type to each car. So in this case, these cars should have class filtered-out-by-car-type added.
I'm noticing the performance is pretty slow with what I currently have below. Also, I'm stuck on how to access the specific type from active_filters associated with the car that is found. Appreciate any help! Thanks so much!!
Cars:
<li data-partner-code="EZ" data-type="XXAR" data-seats="2" data-bags="2" data-prepaid="Y" data-transmission="Automatic" data-unlimited-miles="Y" data-price="84.81" class="listing">
<li data-partner-code="AV" data-type="SFAR" data-seats="4" data-bags="2" data-prepaid="N" data-transmission="Automatic" data-unlimited-miles="Y" data-price="125.54" class="listing">
<li data-partner-code="BU" data-type="CCAR" data-seats="4" data-bags="2" data-prepaid="N" data-transmission="Automatic" data-unlimited-miles="N" data-price="65.42" class="listing">
<li data-partner-code="BU" data-type="CCAR" data-seats="4" data-bags="2" data-prepaid="N" data-transmission="Automatic" data-unlimited-miles="N" data-price="65.42" class="listing">
<li data-partner-code="FX" data-type="MCAR" data-seats="2" data-bags="1" data-prepaid="N" data-transmission="Automatic" data-unlimited-miles="N" data-price="32.00" class="listing">
Active Filters:
{id: "data-seats", value: "1", type: "filtered-out-by-seats"}
{id: "data-bags", value: "2", type: "filtered-out-by-bags"}
{id: "data-partner-code", value: "ET,EY,BU", type: "filtered-out-by-company"}
{id: "data-type", value: "IFAR,SFAR,PGAR,RFAR,FFAR,XXAR", type: "filtered-out-by-car-type"}
Current Code:
cars.forEach(function(car)
{
var found = active_filters.find(function(filter) {
var filter_value = filter.value.split(","); // getting unique value
for (var i=0; i<filter_value.length; i++)
{
if (car.attr(filter.id) === filter_value[i])
{
return car; // Why is this returning active_filters element instead of car?
}
}
});
// Todo: How can I access active_filters.type associated to the car that was found?
if (!found)
{
car.addClass(active_filters.type); // ?
}
});
Your requirements aren't completely clear to me, but the problem seems tailor-made for basic array operations, so perhaps I can offer a framework for solving it that you can fill in with the details.
First, it seems that the basic idea is to filter to cars array to a subset. It turns out there's an Array method just for that called, naturally, filter
const filtered_cars = cars.filter(car => {
// This function will get passed each car in turn. Return
// true if the car should be kept in the list, false otherwise.
});
Now, for each car, I think you want to check all of the active filters. If any of the active filters match, the car should be kept. Again, there's an Array method, in this case it's some.
const filtered_cars = cars.filter(car => {
return active_filters.some(filter => {
// Within this function, we have a car variable, and a filter
// variable. We want to return true if the car matches the
// filter, false otherwise
});
});
It appears from your description that each active filter may have multiple
values, separated by commas. We need to extract those into an array. We can also extract the appropriate car attribute for the filter.
const filtered_cars = cars.filter(car => {
return active_filters.some(filter => {
const values = filter.value.split(",");
const attribute = car.getAttribute(filter.id);
// Return true if the attribute is in the set of values
});
});
Once again we can make use of some
const filtered_cars = cars.filter(car => {
return active_filters.some(filter => {
const values = filter.value.split(",");
const attribute = car.getAttribute(filter.id);
return values.some(value => {
return value === attribute;
});
});
});
At this point, we have reduced the cars array to only those elements that match the filters, but we haven't added the type to those cars that didn't make the filter. To do that, we have to replace the first some with a forEach to ensure that we loop through all the filters instead of stopping at the first match. Also we want to either add or remove the special class as appropriate.
const filtered_cars = cars.filter(car => {
let keep_car = false;
active_filters.forEach(filter => {
const values = filter.value.split(",");
const attribute = car.getAttribute(filter.id);
const matched = values.some(value => {
return value === attribute;
});
car.classList.toggle(filter.type, !matched);
keep_car = keep_car || matched;
});
return keep_car;
});
Like I said, I'm not sure if that code is exactly what you want, as I may have misunderstood the problem. But hopefully it's enough to get you past the current road block.

update 2nd item when the 1st item is the same - reactjs

My main state:
this.state = {
list: []
}
I have a form w/c takes 2 separate arguments: listItem and quantity
render () {
return (
<div>
{this.state.error && <p>{this.state.error}</p>}
<form onSubmit={this.handleAddOption}>
<input type="text" placeholder="description" name="description" /> <br/>
<input type="number" placeholder="quantity" name="quantity" /> <br/><br/>
<button>Add Grocery</button>
</form>
</div>
);
}
}
So basically the two forms are being submitted to the handleAddOption function:
handleAddOption(description, quantity){
if (!description && !quantity) {
return 'Enter valid description and quantity to add item';
} else if (this.state.list.indexOf(description) > -1) {
// must update the quantity
}
this.setState((prevState) => ({
list: prevState.list.concat(description, quantity)
}));
}
So basically the list is an array. There are two things I want to do here:
1. I need to add this two to my main array list state and render them side by side on the screen like:
item1 1
item2 2
As of the moment, I am only concatenating both as text w/c is not a good idea since I need to update the quantity later.
I want to find a way to update the quantity if the same description was placed to the to the form for instance:
1st Input:
item1 1
2nd Input:
item1 5
So it must update the item1 quantity to 5
Any idea how I can handle this?
In order to save the information to an array, we need to figure out the location of the description inside of the array.
You're using the concat function in your example. This function add the two items to the array, but as separate entries. I would recommend you to save the information to a dictionary, this combines the values into a single entry. In JavaScript, we can do this using objects:
prevState.list.push({
description: description,
quantity: quantity
});
In order to get the description from the object, we use the dot notation.
We would save an object to a variable, let's name it entry, and access the description like:
entry.description
In order to make this work, we are supposed to change the function a little bit. Since we can't just check for the presence of a value, we need to loop over the entries of the list. When we do, we have to check whether the descriptions match, if none does, we add the new entry
handleAddOption(description, quantity){
var hasBeenFound = false;
prevState.list.forEach(function (entry) {
if (entry.description === description) {
hasBeenFound = true;
entry.quantity = quantity;
}
});
if (!hasBeenFound) {
elements.push({description: description, quantity: quantity})
}
}
I hope my description made a little sense and that you are able to continue.
Your handleAddOption function edit like this.
handleAddOption = (e) => {
e.preventDefault();
let description = e.target[0].value;
let quantity = e.target[1].value;
if (!description && !quantity) {
return 'Enter valid description and quantity to add item';
} else {
const list = this.state.list.map((el, i) => {
if (el.indexOf(description) > -1) {
// must update the quantity
}
return (el)
});
}
this.setState((prevState, props) => ({
list: prevState.list.concat(description + ' ' + quantity)
}));
}

Categories

Resources