Destructuring an array to create html elements - javascript

i am destructuring an array to create html elements based on the data but i am finding a hard time figuring out how to remove the ',' after destructuring...
const elements = data.map((links) => {
const keys = Object.keys(links);
return `<div class="links"><p class="${keys[0]}">${links.website}</p>
${links.userName}</div>`;
});
result:
<div class="links"><p class="website">Linkedin</p>
André Silveira</div> **,**
the ',' is appearing on the DOM, how do i remove it ?
I tried to destructuring it to a string but then i am not being able to create elements based on criteria.
Here is the data:
export const data = [
{
website: "Linkedin",
url: "https://www.linkedin.com/in/andresilveira717",
userName: "André Silveira"
},
{
website: "Github",
url: "https://github.com/the717q",
userName: "#the717q"
},
{
website: "Twitter",
url: "https://twitter.com/the717q",
userName: "#the717q"
}
];

When you are attempting to insert a HTML string into the DOM, ensure it is not an array of strings instead of a string. Otherwise you will see commas in the output (most likely due to Array.prototype.toString() being implicitly called on the array).
You can use elements.join('') to get a html string of all the elements without commas in between them.
const data = [
{
website: "Linkedin",
url: "https://www.linkedin.com/in/andresilveira717",
userName: "André Silveira"
},
{
website: "Github",
url: "https://github.com/the717q",
userName: "#the717q"
},
{
website: "Twitter",
url: "https://twitter.com/the717q",
userName: "#the717q"
}
];
const elements = data.map((links) => {
const keys = Object.keys(links);
return `<div class="links"><p class="${keys[0]}">${links.website}</p>
${links.userName}</div>`;
});
document.querySelector('#root').insertAdjacentHTML('beforeEnd', elements.join(''))
<div id="root"></div>

Related

Having issue with getting value from object variable. No errors showing

I created an array called animals containing two objects. I want to get a value from the name variable in the object animals and insert that value in a return statement in the map method. I used ${} to access the variable.
const Animals = [{
name: "Lion",
type: "Carnivore",
},
{
name: "Cow",
type: "Herbivore",
},
];
window.addEventListener("DOMContentLoaded", function() {
let display = Animals.map(function(item) {
return '<h1>${item.name}</h1>';
});
console.log(display);
});
Now I'm supposed to get in the console an array of two items containing the values of the variables -- the result should look like this ['<h1>Lion</h1>', '<h1>Cow</h1>']. But instead I get this ['<h1>${item.name}</h1>', '<h1>${item.name}</h1>']. As you can clearly see, for some reason the ${} was unable to access the variable and get the value. I don't know why this's happening. Console log shows no errors. Plz help me resolve this issue. Thanks in advance.
Check in your code instead of:
'<h1>${item.name}</h1>'
Should be:
`<h1>${item.name}</h1>`
Here is the documentation for Template literals (Template strings)
Demo:
const Animals = [{
name: "Lion",
type: "Carnivore",
},
{
name: "Cow",
type: "Herbivore",
},
]
const display = Animals.map(({ name }) => `<h1>${name}</h1>`)
console.log(display)
Variables inside ${...} structures are template/string literals syntax but in order for them to work they need to be enclosed with backticks instead of single/double quotes.
const animals=[{name:"Lion",type:"Carnivore"},{name:"Cow",type:"Herbivore"}];
window.addEventListener("DOMContentLoaded", function() {
const display = animals.map(function(item) {
return `<h1>${item.name}</h1>`;
});
console.log(display);
});
const Animals = [{
name: "Lion",
type: "Carnivore",
},
{
name: "Cow",
type: "Herbivore",
},
];
window.addEventListener("DOMContentLoaded", function() {
let display = Animals.map(function(item) {
return '<h1>'+item.name+'</h1>';
// return `<h1>${item.name}</h1>`;
});
console.log(display);
});

GraphQL mutation using template literal types ${}

I am currently having issues with Graphql mutation. Hard coding updating elements works but option 2 where I pass in argument does not.
On Google Dev Tools Network, I see I am passing [object Object] as request for elements.
I tried changing to code below which resulted in type any error and duplicate identifier args error.
`{args.elements}`
Any tips appreciated.
Also, I am not using variables as the api does not seem to accept them??
api.ts OPTION 1: WORKS
export const mutateReq = (args: TW): AxiosPromise<TW[]> => {
const query = `
mutation {
update ( id:"${args.id}", name:"${args.name}", iconFile:"${args.iconFile}", elements:[
[
{id:"2",name:"element2",link:"https:",elements:[{id:"1",name:"element1",link:"https://",elements:[]}]}
],
[
{id:"3",name:"element3",link:"https://",elements:[{id:"4", name: "wr", link: "http://", elements: []}]}
],
[]
]){
id
name
iconFile
elements {
id name link
elements {
id name link
}
}
}
}`;
return axios({
url: url,
method: 'post',
headers: {
'Content-Type': 'application/json',
},
data: {
query: query,
},
});
};
api.ts OPTION 2: DOES NOT WORK
export const mutateReq = (args: TWorkSpace): AxiosPromise<TWorkSpace[]> => {
const query = `
mutation {
update ( id:"${args.id}" name:"${args.name}" iconFile:"${args.iconFile}" elements:${args.elements}){
id
name
iconFile
elements {
id name link
elements {
id name link
}
}
}
}`;
return axios({
url: url,
method: 'post',
headers: {
'Content-Type': 'application/json',
},
data: {
query: query,
},
});
};
args data type
{
id: "1" name: "1" iconFile: "icon.png"
elements: [
[
{id:"2",name:"element2",link:"https://",elements:[{id:"1",name:"element1",link:"https://",elements:[]}]}
],
[
{id:"3",name:"element3",link:"https://",elements:[{id:"4", name: "wr", link: "http:", elements: []}]}
],
[]
]
}
Your GQL query is a string and when you try elements:${args.elements} it will try to convert the object to a string which will most likely liik like [object Object], but what you need to do is convert it to a JSON string which will give you the output you are looking for.
Try:
elements:${JSON.stringify(args.elements)}

React TypeScript right way to set select value and state

I am trying to learn using TypeScript in my React projects.
I made a type for the incoming data format (name and url).
type PokedexType = {
name: string;
url: string;
}
The data returned from the API is an array of objects (with name and url).
{
"results": [
{
"name": "national",
"url": "https://pokeapi.co/api/v2/pokedex/1/"
},
{
"name": "kanto",
"url": "https://pokeapi.co/api/v2/pokedex/2/"
},
// ...
];
}
In my useEffect(), I am storing these objects in a state with setState().
useEffect(() => {
api.get('/pokedex')
.then((response) => {
setPokedex(response.data.results);
})
.catch((error) => {
console.log(error);
});
});
Because the API returns an array, I am confused about the correct way to setup useState().
// this works
const [pokedex, setPokedex] = useState<Array<PokedexType>>([{ name: "", url: "" }]);
// these also work
const [pokedex, setPokedex] = useState<PokedexType>({ name: "", url: "" });
const [pokedex, setPokedex] = useState<Array<PokedexType>>();
const [pokedex, setPokedex] = useState(); // (with checking)
I understand that specifying type is for type checking, but if the state is overwritten immediately, does this matter?
I am trying to set the states name (i.name) as value for my select, what would be the correct way to do this? Since the state is now an array, how can I set the value to the corresponding property (like this)?
<select value={pokedex.name}>
You can't just say pokedex.name. pokedex is an array, so you have to loop through that array. e.g.
//just a mock, will come from your ajax request
const pokedex = [
{
"name": "national",
"url": "https://pokeapi.co/api/v2/pokedex/1/"
},
{
"name": "kanto",
"url": "https://pokeapi.co/api/v2/pokedex/2/"
}
]
const Select = () => ( <select >
{pokedex.map(el => < option value = {el.name} >{el.name}</option>)}
</select>)
// Render it
ReactDOM.render( <
Select / > ,
document.getElementById("react")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="react"></div>
Take also a look at interfaces:
interface IPokedex {
name: string;
url: string;
}
const [pokedex, setPokedex] = useState<IPokedex[]>([{ name: "", url: "" }]);

Mongoose - Populate Array With Reference Property

I have an array of Tags in my Post schema:
tags: [ { type: Schema.Types.ObjectId, ref: 'Tag' } ],
Tag looks like this:
{ name: String }
When I populate the tags array it is of course populated with tag object literals.
Is there a way I can instead have mongoose populate the array with only the name string from the tag?
I have tried only specifying the name, but then name is returned within an object literal.
Currently the population outputs:
[ { name: 'React' }, { name: 'JavaScript' } ]
But I would like it to be:
[ 'React', 'JavaScript']
Is there a way to do this with Mongoose ?
You can make use of 'post' Query Middleware function. This function will be triggered before the actual data is returned by Model.find() or Model.findOne() query. Inside the function you can use Array.map to transform the data to required format.
schema.post('findOne', function(doc) {
// Transform the doc here.
// Example:
// doc.tags = doc.tags.map(tag => tag.name);
});
You could also do the same for handling Model.find().
schema.post('find', function(docs) {
// Transform the doc here.
// Example:
// docs = docs.map(doc => {
// doc.tags = doc.tags.map(tag => tag.name);
// return doc;
// });
});
You can use a virtual that returns a reduction of the tags array:
schema.virtual('plainTags').get(function () {
// first, validate if the 'tags' path is populated
if (!this.populated('tags')) {
return this.tags
}
return this.tags.reduce(function(col, Tag) {
col.push(Tag.name) return col
}, [])
})

Redux normalizr - nested API responses

How can I use normalizr to deal with nested standardised JSON API responses that are key via the { data: ... } standard?
For example a Book
{
data: {
title: 'Lord of the Rings',
pages: 9250,
publisher: {
data: {
name: 'HarperCollins LLC',
address: 'Big building next to the river',
city: 'Amsterdam'
},
},
author: {
data: {
name: 'J.R.R Tolkien',
country: 'UK',
age: 124,
}
}
}
}
How would I design schemas to deal with the nested data key?
For each entity in your response, you should create it's own schema.In your example, we have three entities - books, authors and publishers:
// schemas.js
import { Schema } from 'normalizr';
const bookSchema = new Schema('book');
const publisherSchema = new Schema('publisher');
const authorSchema = new Schema('author');
If some entity contains nested data which should be normalized, we need to use define method of it schema.This method accepts an object with nesting rules.If we need to normalize publisher and author props of book entity, we should pass an object to define function with same structure as our response:
// schemas.js
bookSchema.define({
data: {
publisher: publisherSchema,
author: authorSchema
}
});
Now we can normalize our response:
import { normalize } from 'normalizr';
import { bookSchema } from './schemas.js';
const response = {
data: {
title: 'Lord of the Rings',
pages: 9250,
publisher: {
data: {
name: 'HarperCollins LLC',
address: 'Big building next to the river',
city: 'Amsterdam'
},
},
author: {
data: {
name: 'J.R.R Tolkien',
country: 'UK',
age: 124,
}
}
}
}
const data = normalize(response, bookSchema);
I believe what you're after is the use of the assignEntity function which can be passed in the options of normalize. In this instance it lets us, where appropriate, filter out the redundant data properties and go straight to the values underneath.
Effectively assignEntity let's you control how each key of data is normalized. Take a look here for a little more on how it works.
I put this together as a demonstration, take a look: http://requirebin.com/?gist=b7d89679202a202d72c7eee24f5408b6. Here's a snippet:
book.define({
data: {
publisher: publisher,
author: author,
characters: normalizr.arrayOf(character)
}}
);
publisher.define({
data: {
country: country
}
});
const result = normalizr.normalize(response, book, { assignEntity: function (output, key, value, input) {
if (key === 'data') {
Object.keys(value).forEach(function(d){
output[d] = value[d];
})
} else {
output[key] = value;
}
}});
Also see in particular Ln 29, where the array of characters has some objects with the information nested within data and some without. All are normalized correctly.
I also added some parts to show how it works with arrays and deeply nested data, see the country model within publisher.
With the data provided you will need a slug due to the absence of id's, which each schema also contains in the example.
Normalizr is fantastic, I hope that helps explain a little more about it :)

Categories