I'm trying to make an array of objects from the browsing history that can become links in a React list.
What this does is takes the history element and pushes it to the user object, then I take the name and ID, and splice it back into the array. I then filter it down to distinct values.
What I am left with, is an array that looks like this:
[{id1,name1},{id2,name2},{id3,name3},"id1","id2","id3"]
which is almost exactly what I want, except if I'm going to map that to create links, I need to get rid of the string values.
It occurred to me to try skipping the history element and just make an array of matches, and any number of other things.
pop and shift don't work to isolate the first object because then the whole function continually returns a single item.
This is the only way I have gotten a result close to what I want, I just need a simple way of filtering out string values from an array after it's created, or maybe before it's mapped out.
const getLead = async _id => {
const res = await axios.get(`/api/leads/${_id}`);
dispatch({
type: GET_LEAD,
payload: res.data
});
const { name } = res.data
const match = { name, _id }
const setPrevious = () => {
const prevLeads = user.prevLeads
const history = createBrowserHistory(getLead);
const prevLead = history.location.pathname.slice(6);
prevLeads.push(prevLead);
return prevLeads;
}
const prevLeads = setPrevious();
const [...spliceLeads] = prevLeads.splice(0,1,match,match);
const distinct = (value, index, self) => {
return self.indexOf(value) === index;
}
const recentLeads = prevLeads.filter(distinct) ;
console.log(spliceLeads)
}
You just check the type in your .filter logic:
const array = [
{ test: 'ing' },
1,
new Date(),
'this should be removed'
];
const result = array.filter(e => typeof e !== 'string');
console.log(result);
The solution what has been provided already works like charm, that should be used for your solution, below I'm providing a bit different way to figure out if the element is a string or not.
I guess filter() is a good way to test each elements on an array and return only the passing once as a result. If you call on each item Object.prototype.toString.call(e) then it will return as a text if you have [object String] or something else. This can be also used to filter out your string values from your array.
See the example below:
const prevLeads = [{id:'id1',name: 'name1'},{id: 'id2',name:'name2'},{id:'id3',name:'name3'},"id1","id2","id3"];
const filter = e => Object.prototype.toString.call(e) !== '[object String]';
const recentLeads = prevLeads.filter(filter);
console.log(recentLeads);
I hope that helps!
Related
I am trying to dynamically add an object to an array of objects, I have been trying to Destructuring the main object but it adds a number to the end of the parent array. This is what I have:
const [data, setData] = useState ([
{
_id:1,
firstName:'Leo',
lastName:'Miller',
telephone:'+569273829',
mail:'leo.miller#gmail.com',
work:[
{_id:1, startWorkDate:'01/01/2015', endWorkDate:'01/02/2017', work:'description...'},
{_id:2, startWorkDate:'01/01/2018', endWorkDate:'01/02/2020', work:'description...'}
]
}];
I generate dynamically this object:
const value = {_id:3, startWorkDate:'01/01/2018', endWorkDate:'01/02/2020', work:'description...'}
I need to add it into data.work and after that update only the description of work._id[3]
I try with this function
const addNewWork = (value) => {
let copyData = [...data, data[0].workExperience.push(value)]
return setData(copyData)
}
but for some reason doesn't add correctly the object. Help please!
You have an array and not an object. Your statement
let copyData = [...data, data[0].workExperience.push(value)]
is doing two things:
mutating the state by doing push(). Which is not the react way.
creating a new array. Also adding a new item to the array, but that is the new length of data[0].workExperience.
The return value of Array.prototoype.push is:
The new length property of the object upon which the method was called.
What you have to do is:
Make a copy of the array. Can use ... (spread operator) here.
Make a copy of the array object you want (first index). Try to add the object to its specific property workExperience.
const addNewWork = (value) => {
let newData = [...data];
let newWorkExperienceArray =
[...data[0].workExperience,value];
let newDataFirstObject = {...data[0], workExperience : newWorkExperienceArray};
newData[0] = newDataFirstObject;
return setData(newData)
}
You can also update the property. I didn't find the relevant code in your question as to what I have to update so I didn't update anything in the third workExperience object.
EDIT: It seems in your code the property name is work and not workExperience. Please confirm. The above code uses workExperience, you can replace it by work if that is the case
You can do this with this simple function:
const addNewWork = (value) => {
let updatedObj = data[0];
updatedObj.work.push(value)
// updates your object each time
let copyData = [updatedObj]
// adds a new object for each call
// let copyData = [...data, updatedObj]
return setData(copyData)
}
Now it updates the object in your state. If you want to add a new object for each call just uncomment let copyData = [...data, updatedObj] and comment out let copyData = [updatedObj]
When you set state for array your setter is a quite bite different
setData(prevData => [...prevData, newItem]) // to add a single item to array
setData(prevData => newArray) // to replace entire array
given an array of objects in users.json:
{"key":"userSubscriptions","value":
[{"channel":"Netflix","user":"Bobby","region":"NA"},
[{"channel":"Netflix","user":"Bobby","region":"EU"},
[{"channel":"Netflix","user":"Jamie","region":"SEA"},
[{"channel":"Prime Video","user":"Bobby","region":"NA"}]}
How would one filter such that the end result will be
console.log(result); // Bobby, your region subscriptions are: Netflix: (NA, EU), Prime Video: (NA)
Thank you!
EDIT: i tried using .filter() & .map() method but no luck so far
you have to use lodash to group data, then map data
var data = {
"key":"userSubscriptions",
"value":
[{"channel":"Netflix","user":"Bobby","region":"NA"},
{"channel":"Netflix","user":"Bobby","region":"EU"},
{"channel":"Netflix","user":"Jamie","region":"SEA"},
{"channel":"Prime Video","user":"Bobby","region":"NA"}]
}
var users = _.chain(data.value)
.groupBy("user").map((value, key) => ({ user: key, data: value })).value();
users.forEach(element => {
console.log(element)
console.log(`${element.user}, your region subscriptions are: Netflix: ${element.data.map(c=>c.channel).join(',')}, Prime Video: ${element.data.map(c=>c.region).join(',')}`)
});
Your JSON data is invalid. However, I think I adapted it to what you intended.
This breaks the data down into a by-user format, and supplies a function to output the Subscriptions and Regions for any named user.
const jsonString = `{"key":"userSubscriptions","value":[{"channel":"Netflix","user":"Bobby","region":"NA"},{"channel":"Netflix","user":"Bobby","region":"EU"},{"channel":"Netflix","user":"Jamie","region":"SEA"},{"channel":"Prime Video","user":"Bobby","region":"NA"}]}`;
const obj = JSON.parse(jsonString); // parse the data from a string into an object
const byUser = obj.value.reduce((acc, o) => { // reduce the "value" array to a single object
if (!acc[o.user]) acc[o.user] = {}; // create acc.userName if it does not exist
if (acc[o.user][o.channel]) acc[o.user][o.channel].push(o.region); // if acc.userName.channelName has an array, add this region to it
else acc[o.user][o.channel] = [o.region]; // else create an array with this region in it
return acc; // keep the created object for the next iteration
}, {});
function printForUser(userName) { // create a function that takes a user's name
const user = byUser[userName]; // take the user object from the byUser object
return Object.keys(user).reduce((acc, k) => { // reduce the keys of the user object to one string
return acc + ` ${k}: (${user[k].join(", ")}),`; // add on each subscription and regions
}, `${userName}, your region subscriptions are:`).slice(0, -1); // initialize the string and remove the last comma
}
console.log( printForUser("Bobby") );
I have removed an element from an array. Now, I need to display which item is deleted and the remaining items, but have been unsuccessful. Suppose, the array looks like:
let person = ['Cercei','Snow','Arya','Sansa']
I have removed 'Snow' and 'Cercei'. So, I need to display two things into two different new array.
delPerson = ['Cercei','Snow']
remArray = ['Arya','Sansa']
How can this be done with JavaScript? In my application, I have delete icon with each and every name so i can remove any name. I want to get the deleted name and remaining name into two different array. Please help me how to do that using javascript or lodash
let me tell you my application code:
let person = personData.map(n => n.name)
let remPerson = person.filter(p => person.indexOf(p) !== -1)
Now, person and remPerson array is showing same value. While comparing the length it is creating the problem.
One way could be to use Array.reduce.
const persons = ['Cercei', 'Snow', 'Arya', 'Sansa'];
const {
deleted,
kept
} = persons.reduce((acc, person) => {
// Note: The deletion condition may vary
if (person === 'Cercei' || person === 'Snow') {
acc.deleted.push(person);
} else {
acc.kept.push(person);
}
return acc;
}, {
deleted: [],
kept: []
});
console.log(deleted);
console.log(kept);
You can use splice, but this will modify your original array. It is unclear to me if that will be ok in the OP's case. Here's Mozilla's documentation on splice: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice
let person = ['Cercei','Snow','Arya','Sansa'];
let delPerson = person.splice(0, 2);
console.log(delPerson);
console.log(person);
You can remove items using splice and also keep track of two separate arrays:
let personData = [{name:'Cercei'},{name:'Snow'},{name:'Arya'},{name:'Sansa'}];
let person = personData.map(n=>n.name);
let removeItems = ['Cercei','Snow'];
let delPerson = [];
removeItems.forEach(item=>{
delPerson.push(
...person.splice( person.indexOf(item), 1 )
)
});
console.log('delPerson: ', delPerson);
console.log('remaining: ', person);
I'm creating a small application for connection to an API and append cards from magic the gathering JSON file onto an HTML webpage.
Those cards should be searchable and for that to happen I need to somehow create a filter()
I'm new and still in school at this subject.
I have pulled out only the card Names in the variable called "arr" and is trying to filter out / or match with a value from the search input field which is "strInput"
document.getElementById("searchButton").addEventListener("click", function(e){
const parentDiv = document.getElementById("cards");
if ( parentDiv.hasChildNodes() === true ) {
removeStuff();
} else {
filteredCards("https://api.magicthegathering.io/v1/cards");
}
}, false)
displayCards("https://api.magicthegathering.io/v1/cards");
function filteredCards(url) {
fetch(url)
.then((resp) => resp.json())
.then((data) => {
let myInput = document.getElementById("search").value;
let strInput = '"' + myInput + '"';
let arr = [];
for ( i in data.cards) {
let jsonValue = data.cards[i];
let name = jsonValue.name;
arr.push(name);
}
let result = strInput.match(arr);
console.log(result);
console.log(arr);
console.log(strInput);
});
};
console.log(arr); // returns NULL even thought the string matches.
There's two ways to do it simply that I could think of, .find() and .filter()
.find() is going to return you the first match, and as a string
.filter() is going to return you the all matches, and as an array
They both work with the same style of code, you're just changing the method name
arr.filter(item => item === strInput) | arr.find(item => item === strInput
Just as a little aside, there's a few things you could swap out to get those sweet sweet brownie points
let arr = [];
for ( i in data.cards) {
let jsonValue = data.cards[i];
let name = jsonValue.name;
arr.push(name);
}
Can instead be wrote using the map function
let arr = data.cards.map((card) => card.name);
.
Also, you don't need to do '"' + myInput + '"'; to make sure something is a string, which is what you might be trying to do there - you can just use myInput.toString() - of course your data might have the names include the quotes, but just in case this is a mistake I thought I'd point it out
The parameter passed to match method is not really a matcher but a string. The method expects a regex to be passed in.
Just build out a simple regex expression and then iterate over the data.cards and add it into the array if the condition passes. You can look at the filter available on the array object.
let myInput = document.getElementById("search").value;
let myInputRegex = new Regex(myInput, 'gi');
let arr = [];
const matchedTokens = data.cards.filter(card => {
return card.name.match(myInputRegex);
});
console.log(matchedTokens);
console.log(strInput);
You can make a method that uses array.Find() and pass in the arr and strInput. array.Find() will find the first match
getName: function (arr, strInput) {
var name = arr.find(n => n === strInput)
return name
}
Here's some more reading from the official mozzila docs
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find
Thanks!
This was exactly what i was looking for :D
let myInput = document.getElementById("search").value;
let myInputRegex = new Regex(myInput, 'gi');
let arr = [];
const matchedTokens = data.cards.filter(card => {
return card.name.match(myInputRegex);
});
console.log(matchedTokens);
console.log(strInput);
I am implementing a filter. it works fine. the problem is it's just matching a single object value instead of all value matching.
Matching means here is, let it be contain any single letter in the value
example: here is my object
{name:"D",color:"Green",size:50}
in case if i pass the filter object as :
let filter1 = {color:"Blu",size:'50'};
at present I am getting single result by matching size. But the color is not matching at all. so the result should be empty.
How to mach all values in the object and get the filtered value.
Live Demo
Code :
const nestedFilter = (targetArray, filters) => targetArray.filter(o => Object.keys(filters).find(k => filters[k].includes(o[k])));
let products = [
{name:"A",color:"Blue",size:70},
{name:"B",color:"Blue",size:60},
{name:"C",color:"Black",size:70},
{name:"D",color:"Green",size:50}
];
let filter1 = {color:"Blu",size:'50'};
console.log(nestedFilter(products, filter1));
Replace the .find invocation with .every. Be aware though that by using includes you expect your property values to be String.
If you want includes to work to other way round, so that the filter value can be a substring of the data, you should do:
const nestedFilter = (targetArray, filters) =>
targetArray.filter(o => Object.keys(filters).every(k =>
String(o[k]).includes(filters[k]))
)
)
The o[k] value needs to be converted to string, as otherwise you cannot apply includes to it (cf. size which is a number)
Check whether every of the Object.entries of the filter passed is equal to the same entry on the object being iterated over. If you want partial matches and are using different types of variables, it sounds like you also need to coerce them to strings first, so you can use .includes.
const nestedFilter = (targetArray, filters) => targetArray.filter(
obj => Object.entries(filters).every(
([key, val]) => String(obj[key]).includes(val)
)
);
let products = [
{name:"A",color:"Blue",size:70},
{name:"B",color:"Blue",size:60},
{name:"C",color:"Black",size:70},
{name:"D",color:"Green",size:50},
{name:"E",color:"Blu",size:'50'}
];
let filter1 = {color:"Blu",size:'70'};
console.log(nestedFilter(products, filter1));