How to solve this forEach loop problem in wp? - wordpress

In one of my WordPress Project, I had to post a get request and render the response data in the front end. To render the data I tried to use the forEach() loop but it always shows undefined but the same thing works fine if I use map().
Now I just want to know what's the problem with forEach(). I am giving both the working and not working code below:
Not working:
getResults() {
$.getJSON(`http://localhost/from_wp_course/wp-json/wp/v2/posts?search=${this.searchField.val()}`, posts => {
this.resultsDiv.html(`
<h2 class="search-overlay__section-title">General Information</h2>
<ul class="link-list min-list">
${posts.forEach(item => `<li>${item.title.rendered}</li>`)}
</ul>
`);
});
}
Working:
getResults() {
$.getJSON(`http://localhost/from_wp_course/wp-json/wp/v2/posts?search=${this.searchField.val()}`, posts => {
this.resultsDiv.html(`
<h2 class="search-overlay__section-title">General Information</h2>
<ul class="link-list min-list">
${posts.map(item => `<li>${item.title.rendered}</li>`).join('')}
</ul>
`);
});
}

.foeEach return value is undefined (why you get the undefined) but .map returns a new array.

Related

How to convert xpath element which contains text to css

I have the following Xpath to locate an element which has the text Manager. I need to use CSS in our Cypress IO automation. My test adds a new item in the Gui by clicking the Add button and types in Manager and clicks the Save button. I want to do an Assertion the text Manager exists when it has been saved. the Assertion is not working due to not finding the correct locator.
Xpath locator:
//span[contains(text(),'Manager')]
I tried to use the following as CSS
cy.get('span:contains("Operator")
The locator is not working I get the following error when i run my code
o
find.form-control3
o 14assertexpected [ <span.form-control>, 2 more... ] to have text Manager, but the text was ManagerUndefinedManager3
AssertionError
Timed out retrying after 10000ms: expected '[ <span.form-control>, 2 more... ]' to have text 'Manager', but the text was 'UndefinedManager'
The first item by default in the list of elements is called Undefined. When a new entry is added it is Manager in the list.
My code snippet is:
static get AudienceTextfieldSavedValue(): Cypress.Chainable<JQuery<HTMLElement>> {
//return cy.get('span:contains("Manager")').should('have.text', 'Manager');
//return cy.get('(ul).find(li with given text)..find(form-control).have "Manager")')
return cy.get('.cdk-drop-list').find('.form-control').should('have.text', 'Manager');
}
it('Add Audience', () => {
Lists.navigateToLists;
Audience.clickAdd;
Audience.AudienceTextfield.type("Manager");
Audience.getSaveButton.click().then(() => {
cy.wait(['#savingAudienceRecord']);
});
Audience.AudienceTextfieldSavedValue.should('have.text', 'Manager');
});
The HTML snippet is:
What is the correct css locator I should use please? Thanks
Riaz
In my understanding, the simplest reproduction of what happens during the test is
DOM starts with two spans
<ul class="cdk-drop-list">
<li><span class="form-control">Manager</span></li>
<li><span class="form-control">Undefined</span></li>
</ul>
You add the new entry and the DOM becomes
<ul class="cdk-drop-list">
<li><span class="form-control">Manager</span></li>
<li><span class="form-control">Undefined</span></li>
<li><span class="form-control">Manager</span></li>
</ul>
You want to check the last entry, so AudienceTextfieldSavedValue() should only select the last span in the list (assuming the save action does not sort the list).
static get AudienceTextfieldSavedValue(): Cypress.Chainable<JQuery<HTMLElement>> {
return cy.get('.cdk-drop-list').find('.form-control')
.last() // assuming the saved field is the last one
.should('have.text', 'Manager');
}
it('Add Audience', () => {
Lists.navigateToLists;
Audience.clickAdd;
Audience.AudienceTextfield.type("Manager");
Audience.getSaveButton.click().then(() => {
cy.wait(['#savingAudienceRecord']);
});
Audience.AudienceTextfieldSavedValue.should('have.text', 'Manager');
});
.should('have.text', 'Manager') is performed twice, so you can perhaps remove it from AudienceTextfieldSavedValue() and just return the last entry.
That way, you can test with different text entry.
You may also want check the number of entries increases from 2 to 3, because if Audience.getSaveButton.click() fails to do the save your test would still pass.
static get AudienceTextfieldSavedValue(): Cypress.Chainable<JQuery<HTMLElement>> {
return cy.get('.cdk-drop-list').find('.form-control')
.last() // assuming the saved field is the last one
}
static get AudienceTextfieldCount(): Cypress.Chainable<JQuery<HTMLElement>> {
return cy.get('.cdk-drop-list').find('.form-control')
.its('length')
}
it('Add Audience', () => {
Lists.navigateToLists;
Audience.AudienceTextfieldCount().should('eq', 2)
Audience.clickAdd;
Audience.AudienceTextfield.type("Manager");
Audience.getSaveButton.click().then(() => {
cy.wait(['#savingAudienceRecord']);
});
Audience.AudienceTextfieldCount().should('eq', 3)
Audience.AudienceTextfieldSavedValue.should('have.text', 'Manager');
});

Data Not Rendering Using Next Js

I'm trying to use data from an API following the steps provided in the Next docs. My data does not render, this is my first foray into React so I'm not sure what I'm missing. Would somebody mind pointing out my error please?
export default function Home({ items }) {
console.log(items) // Items listed in the console fine
return (
<ul>
{items.map((item, index) => {
<li key={index}>{item.description}</li>
})}
</ul>
)
}
export async function getStaticProps() {
// Get Data Here
return { props: {
items
}}
};
As you can see by my note above, the console lists the items as expected. I can also see the items array in the React Dev Tools in chrome.
The below console.logs as expected but again nothing is rendered to the browser.
export default function Home({items}) {
return (
<ul>
{items.map((item, index) => {
console.log(item.description);
<li key={index}>{item.description}</li>
})}
</ul>
)
}
{items.map((item, index) => {
console.log(item.description);
<li key={index}>{item.description}</li>
})}
should be:
{items.map((item, index) => {
console.log(item.description);
return <li key={index}>{item.description}</li>
})}

Use setState to change the value of a grandchild object

Everything I have tried from what I can find doesn't seem to be working. I'm really curious how to access and edit grandchild objects located in the state with react. If anyone could tell me what I'm doing wrong, it would be very helpful.
https://codesandbox.io/s/0mo32q85pp
Take a look at the following code...
App.js
lines: 41-58
getHomeworld = URL => {
fetch(URL)
.then(res => {
return res.json();
})
.then(homeWorldObject => {
console.log(homeWorldObject);
// this.setState({ <- Why isn't this working????
// ...this.state.starwarsChars,
// ...this.state.nextPage,
// ...this.state.prevPage,
// ...this.state.starwarsChars.homeworld = homeWorldObject
// });
})
.catch(err => {
throw new Error(err);
});
};
lines: 86-89
<CharacterList
characters={this.state.starwarsChars}
getHomeworld={this.getHomeworld}
/>
CharacterList.js
lines: 8-12
<Character
key={character.name}
characterDetails={character}
getHomeworld={props.getHomeworld}
/>
Character.js
lines: 18-29
{Object.keys(props.characterDetails).includes("homeworld") ? (
<div className="character-homeworld">
<Homeworld
homeworld={props.getHomeworld(props.characterDetails.homeworld)}
/>
</div>
) : (
<div className="character-homeworld">
<h4>Homeworld</h4>
<p>None</p>
</div>
)}
Homeworld.js
lines: 7-10
<div className="homeworld-details">
<p>Name: {props.name}</p>
<p>Rotation Period: {props.rotation_period}</p>
</div>
Expected Output:
If you look on the sandbox webpage, the "Name" and "Rotation Period" (Under "Homeworld") should display the values from here: https://swapi.co/api/planets/1/
Is there anyone who can help me figure this out?
EDIT:
I got really close making these changes (using my local machine, the code on the sandbox is still the original)...
App.js
let temp = {...this.state.starwarsChars} // use spread operator to clone it, so you don't mutate state on next line;
for (let character in temp) {
if (temp[character].homeworld === URL) {
temp[character].homeworld = homeWorldObject;
}
}
// console.log(temp);
this.setState({
starwarsChars: temp
});
Character.js
const Character = props => {
props.getHomeworld(props.characterDetails.homeworld);
console.log(props.characterDetails); // returns object{homeworld: {object}}
console.log(props.characterDetails.homeworld); // returns url
and...
<div className="character-homeworld">
<Homeworld
homeworld={props.characterDetails.homeworld}/>
</div>
However, the issue now is if I do console.log(props.characterDetails.homeworld);, it logs homeworld: url
and...
if I do console.log(props.characterDetails);, it logs the property of the character object as homeworld: {object}
...
What I want is the 2nd one, and I'm not sure why it's not consistent.
Update
For some strange reason, codesandbox is console logging both urls, and when I run with yarn start, it logs the url for one, and the object for another. Because of this... I am adding the github link here -> https://github.com/jamespagedev/Sprint-Challenge-React-Wars (so the error can properly be reproduced)
Edit 2:
I changed the sandbox code to the following so we are now only worrying about the code in 1 file -> https://codesandbox.io/s/0mo32q85pp
Here is the issue I am now seeing, and I'm not sure how to solve it...
getHomeworld = URL => {
let home;
fetch(URL)
.then(res => res.json())
.then(homeWorldObject => {
home = homeWorldObject;
console.log(home); // home is an object
});
console.log(home); // why is home undefined?
return home;
};
I've tried doing return homeWorldObject, but the main function just returns undefined. After doing the console logging, that was what I found, and I'm not sure why that is happening...

WP API and JS : Cannot read property 'wp:featuredmedia' of undefined

I write a component to display a list WP posts on a page build with nuxt.js and I just can not display the featured image.
The Vue Component
<template>
<div class="references__grid">
<div class="references__item" v-for="item in references">
<h3><nuxt-link :to="slugToUrl(item.slug)"><h2 class="is-title">{{ item.title }}</h2></nuxt-link></h3>
<div v-html="item.excerpt"></div>
<div>{{ item.image }}</div>
<strong class="more"><nuxt-link :to="slugToUrl(item.slug)">Lire la suite</nuxt-link></strong>
</div>
</div>
</template>
The request
getReferences() {
return new Promise((resolve, reject) => {
request.defaults.baseURL = this.baseUrl;
request.get(`posts?categories=46&per_page=6&_embedded`).then(response => {
const data = [...response.data];
if (response.status === 200 && response.data.length > 0) {
const filtered = {
total: response.headers["x-wp-total"],
totalPages: response.headers["x-wp-totalpages"],
data: data.map(item => ({
id: item.id,
title: item.title.rendered,
content: item.content.rendered,
excerpt: item.excerpt.rendered,
slug: item.slug,
image: item._embedded["wp:featuredmedia"][0].media_details.sizes.full.source_url
}))
};
resolve(filtered);
} else {
reject(response);
}
});
});
},
The WP Api seems ok: https://www.agencedebord.com/wp-json/wp/v2/posts?categories=46&per_page=61&_embed
The error message:
ERROR
TypeError: Cannot read property '0' of undefined
server-bundle.js:1525 filtered.data.data.map.item
server-bundle.js:1525:56
Array.map
server-bundle.js:1519 >__WEBPACK_IMPORTED_MODULE_1_axios___default.a.get.then .response
server-bundle.js:1519:24
next_tick.js:160 process._tickCallback
internal/process/next_tick.js:160:7
So why item._embedded is undefined?
There is no problem for item.id or item.slug... any clarification is appreciated.
Finally, I did not use "_embed" but I add a new endpoint following this answer : Get Image URL instead of Attachment Id in Rest API
I think that the request url is not correct, you should use _embed not _embedded
So it will be request.get(posts?categories=46&per_page=6&_embed)
Otherwise, the _embedded part will be missing in the json response.
The problem is sometimes item._embedded['wp:featuredmedia'] is returning undefined, you can confirm you get that by console.log(item._embedded['wp:featuredmedia']), the solution for that by wrapping it in if condition, if it not undefined to proceed if(item._embedded['wp:featuredmedia']){ return let imageUrl = item._embedded["wp:featuredmedia"][0].media_details.sizes.full.source_url
} else { return null}
I had one post that was giving this error. I had the if/else setup properly but it was still erroring. I went to the problem post and resaved the featured image and also changed to the ajax to load .full.source_url instead of .medium.source_url and that fixed the error.
I imported some photos from another wordpress. some of them had not featured images yet they somehow acting like they have. (has_post_thumbnail() was acting same way and returns true for that posts)
My solution is checking if they 'really' have thumbnail:
if(post.featured_media == 0 || post._embedded['wp:featuredmedia'][0].media_details == undefined){
imageSource = null;
}
else{
imageSource = post._embedded['wp:featuredmedia'][0].media_details.sizes.full.source_url;
}

trying to render a list. nothing showing on screen

Using Meteor and React. Trying to render a list of data from the server onto the client. the server's data looks like this:
Searches.insert({text: data.items[i].snippet.title});
if(Meteor.isClient) {
Searches = new Meteor.Collection('searches');
Meteor.subscribe('allSearches');
}
....
renderTasks(){
return this.data.searches.map((searches) => {
return <SearchResultItem searches={searches} />;
});
},
....
<ul>
{this.renderTasks()}
</ul>
....
SearchResultItem = React.createClass({
render(){
return
<li>
{this.props.searches.text}
</li>
}
});
You need to provide an unique key-prop to your dynamic child elements
Dynamic Children
The situation gets more complicated when the children are shuffled around (as in search results) or if new components are added onto the front of the list (as in streams). In these cases where the identity and state of each child must be maintained across render passes, you can uniquely identify each child by assigning it a key:
render: function() {
var results = this.props.results;
return (
<ol>
{results.map(function(result) {
return <li key={result.id}>{result.text}</li>;
})}
</ol>
);
}
(REF: https://facebook.github.io/react/docs/multiple-components.html#dynamic-children)
In your case:
renderTasks(){
return this.data.searches.map((searches, i) => {
return <SearchResultItem key={i} searches={searches} />;
});
}

Resources