Read-only variable when assigning object to variable - javascript

I have a variable named picture that is taking in a thumbnail that is an address for a picture. I want to use that as the src path for my img tag. How do I accomplish this? From what i'm understanding is React generates render() first and then componentDidMount(), but my code is returning Cannot set property 'src' of null.
Update
I changed the code based off suggested comments. I loaded the state in my constructor so that gets defined before everything else. But now it says picture" is read-only which is where --> is
Code
constructor(props) {
super(props);
this.props.getVideos();
const picture = {};
this.props.getVideos();
if (this.props.videos == null) {
console.log("It's null");
} else {
const videos = this.props.videos.video.map(video => {
<h5 key={video._id}>{video.thumbnail}</h5>;
--> picture = video.thumbnail;
});
}
}
componentDidMount() {
console.log(picture);
}
Snippet of return in render
<div className="explore">
<div className="row">
<div className="row__inner">
<div className="tile">
<div className="tile__media">
<img className="tile__img" id="thumbnail" src={picture} alt="" />
</div>
<div className="tile__details">
<div className="tile__title">
<h5>Impact Dallas</h5>
</div>
</div>
</div>
Update
I changed the code based off suggested comments. I loaded the state in my constructor so that gets defined before everything else. But now it says picture" is read-only which is where --> is

Related

Click to change image is changing the wrong one

So I'm working on a website that has a lot of movies, and people can choose what movies are they favorite, and for that, I have a star image that can be clicked and when clicked that image will change to another one
Like this:
To this:
The problem I have is that the only image that change is the first one, When I click, for example on the star next to the Ratatouille movie, it will change the first star
This is the HTML:
const getMovieHtml = (movie) => `<div class="movie">
<h2>${movie.title}</h2>
<img onclick="bottonclick()" id="estrelinhas" src="./icons/empty-star.png" alt="estrela vazia" width=40>
<div class="content">
<img src="${movie.posterUrl}" alt="${movie.title}" />
<div class="text">
<p>${movie.summary}</p>
<div class="year">${movie.year}</div>
<div><strong>Directors:</strong> ${movie.director}</div>
<div><strong>Actors:</strong> ${movie.actors}</div>
</div>
</div>
</div>`;
And this is the arrow function I used to make the star change:
const bottonclick = () => {
if (document.getElementById("estrelinhas").src.includes("empty-star.png")) {
document.getElementById("estrelinhas").src = "./icons/filled-star.png";
} else {
document.getElementById("estrelinhas").src = "./icons/empty-star.png";
}
};
ID attributes of HTML elements should be unique. If you don't have unique ID's the code doesn't know which star to update. Read more about IDs here: https://www.w3schools.com/html/html_id.asp
To fix this, a solution would be to use a unique identifier for each image, so that when you click "favourite" it knows which star to reference.
Assuming for example that the movie.posterURL is unique you can use that as the ID, however the data from wherever you are getting the movie from might already have a unique identifier that you could pass to the id attribute of the image instead
Your code could look something like this:
const getMovieHtml = (movie) => `<div class="movie">
<h2>${movie.title}</h2>
<img onclick="bottonclick(e)" id="${movie.posterUrl}" src="./icons/empty-star.png" alt="estrela vazia" width=40>
<div class="content">
<img src="${movie.posterUrl}" alt="${movie.title}" />
<div class="text">
<p>${movie.summary}</p>
<div class="year">${movie.year}</div>
<div><strong>Directors:</strong> ${movie.director}</div>
<div><strong>Actors:</strong> ${movie.actors}</div>
</div>
</div>
</div>`;
const buttonClick = (e) => {
const star = document.getElementById(e.target.id);
if (star.src.includes("empty-star.png")) {
star.src = "./icons/filled-star.png";
} else {
star.src = "./icons/empty-star.png";
}
}
beacuse you getElementById, so you not take all containers,
but you get 1, first,
change getElementById for querySelectorAll and give there some id,
to localizate in DOM ,
buttonClick(e)
and in
function buttonClick(e) {
e.target.value/id/or something
}

How to track changes of a referenced element with React?

I have a problem which requires me to store the texted of a referenced element in an array.
Now, I first want to display the text for each element(paragraph element with "ebookName" class) in the console, before storing it in the array.
But I have been having problems... Whenever I click an element, the console just logs the previous elements text always. I want for each paragraph element to log that specific elements text, not the previous one
Link to JS code:
import React from 'react'
import "./Styles/Ebook.css"
import { useRef } from 'react';
function Ebook() {
const bookName = useRef();
let ebookData = JSON.parse(sessionStorage.getItem("ebook"));
/*function that displays the specific text of a specific element onto the console*/
const elementLogFunction = () =>{
console.log(bookName.current)
}
return (
<section id="musicRender">
{ebookData.results.map((ebook, i)=>{
return (
<div key={i} className='ebookContentContainer'>
<div className="ebookPicture">
<img src={ebook.artworkUrl100} alt={ebook.trackName} />
</div>
<div className="ebook-description">
<p className="ebookAuthor">Author: {ebook.artistName}</p>
<p ref={bookName} className='ebookAName'>Book Name: {ebook.trackName}</p>
<p className="price">Price: R{(ebook.price * 15.36).toFixed(0)}</p>
<button onClick={elementLogFunction} className="favourites-btn">Add To Favourites</button>
</div>
</div>)
})}
</section>
)
}
export default Ebook
According to your code, ref is only referred to the same data, and the new one will override the old one. In your case, the last book data will be kept.
If you want to have individual book data separately, you can pass a param to elementLogFunction.
You also shouldn't read sessionStorage every rendering. This behavior causes a performance issue due to getting data multiple times. You can use useEffect to read data only once after the first rendering.
function Ebook() {
const [ebookData, setEbookData] = React.useState([]);
//only add data for the first rendering
useEffect(() => {
setEbookData(JSON.parse(sessionStorage.getItem("ebook")));
}, []);
/*function that displays the specific text of a specific element onto the console*/
const elementLogFunction = (ebook) =>{
console.log(ebook.trackName)
}
return (
<section id="musicRender">
{ebookData.results.map((ebook, i)=>{
return (
<div key={i} className='ebookContentContainer'>
<div className="ebookPicture">
<img src={ebook.artworkUrl100} alt={ebook.trackName} />
</div>
<div className="ebook-description">
<p className="ebookAuthor">Author: {ebook.artistName}</p>
<p ref={bookName} className='ebookAName'>Book Name: {ebook.trackName}</p>
<p className="price">Price: R{(ebook.price * 15.36).toFixed(0)}</p>
<button onClick={() => elementLogFunction(ebook)} className="favourites-btn">Add To Favourites</button>
</div>
</div>)
})}
</section>
)
}
export default Ebook

Angular - Use a default image if image does not exist on server

I have a component that will display a cover image. The user can upload a cover image and the component will display the user uploaded image. If the user doesn't upload an image, then I want to display a default image.
If there is no user uploaded image I want to return an error and call the changeSource(event), which should in theory bind a new image url to the img src. However I'm getting undefined for the event.target.src and I'm seeing a blank space where the default image should be. It works fine when displaying the custom image.
component.html
<div *ngFor="let coverPhoto of coverPhotos">
<img src="{{coverPhoto}}"
(error) ="changeSource($event)" />
</div>
component.ts
this.myService.getPhotos(ImageType.Cover, this.id).subscribe(result => {
this.coverPhotos = result;
}, error => {
this.errors = error;
this.changeSource(event);
}, () => {
}
);
changeSource(event) {
event.target.src = "https://imageurl";
}
directly use (where defaultImage is a variable in ts file which holds the default image path) -
(error)="$event.target.src = defaultImage"
your HTML -
<div *ngFor="let coverPhoto of coverPhotos">
<img src="{{ coverPhoto }}" (error)="$event.target.src = defaultImage" />
</div>
Working example here.
You are passing event from this code in ts, which is obviously undefined, and you don't need to call this function from here -
this.myService.getPhotos(ImageType.Cover, this.id).subscribe(result => {
this.coverPhotos = result;
}, error => {
this.errors = error;
this.changeSource(event);
}, () => {
}
);
The *ngFor was throwing it off. Removing this seemed to solve the problem. Not quite sure why so will post an edit when I discover why.
<div>
<img src="{{coverPhotos}}"
(error)="$event.target.src = defaultImage" />
</div>

Vue getter returns undefined when page reload

I have a blog with some posts. When you click on the preview you will redirect on the page post.
On the page of the post, I use a getter to load the correct post (I use the find function to return object.name which corresponds to the correct object in the array of objects).
const state = {
ricettario: [], // data that contains all recipes (array of objects)
}
const actions = {
// Bind State and Firestore collection
init: firestoreAction(({ bindFirestoreRef }) => {
bindFirestoreRef('ricettario', db.collection('____').orderBy('data'))
})
const getters = {
caricaRicetta(state) {
console.log('Vuex Getter FIRED => ', state.ricettario)
return nameParamByComponent => state.ricettario.find(ricetta => {
return ricetta.name === nameParamByComponent
})
}
}
In the component, I call the getter in the computed property
computed: {
...mapGetters('ricettaStore', ['caricaRicetta']),
ricetta() {
return this.caricaRicetta(this.slug) // this.slug is the prop of the URL (by Router)
}
}
Anything goes in the right way but when I reload the page in the POST PAGE, the getter will fire 2 times:
1. return an error because the state is null
2. return the correct object
// screen below
So everything works fine from the front but not at all in the console and in the App.
I think the correct way is to call the getters in the created hook. What I've to change? It is a problem with the computed prop, getters or state?
POST PAGE:
<template>
<div v-if="ricetta.validate === true" id="sezione-ricetta">
<div class="container">
<div class="row">
<div class="col s12 m10 offset-m1 l8 offset-l2">
<img
class="img-fluid"
:src="ricetta.img"
:alt="'Ricetta ' + ricetta.titolo"
:title="ricetta.titolo"
/>
</div>
</div>
</div>
</div>
<div v-else>
...
</div>
</template>
You are trying to validate undifined property. So you need to check ricetta first.
Try like this:
<div v-if="ricetta && ricetta.validate === true" id="sezione-ricetta">
Database synchronization is asynchronous, ricettario is initially an empty array. Computed value is recomputed once synchronization is finished and ricettario array is filled, the component is updated.
Even if ricettario weren't empty, find may return undefined if it finds nothing. This needs to be handled where ricetta is used:
<div v-if="ricetta && ricetta.validate" id="sezione-ricetta">
The error log is quite explicit, there is a xxx.validate somewhere in your Ricetta component template, but that xxx is undefined.
Because of this, your app crashes and stops working. I doubt it has anything to do with Vuex

Render a component within another in React

When a state is changed, React triggers componentDidUpdate() method, and by then I do:
componentDidUpdate: function () {
React.render(new SubmitButton, $('.uploader-submit').get(0));
}
As you saw, I'm rendering a SubmitButton when a specific state is changed, but my question is: is this the best behavior to get this feature done?
My scenario is: I'm uploading a photo. When the input[type=file] is changed, I create a new state property and then the componentDidUpdate() is triggered, invoking the SubmitButton.
This is my render() method:
render: function () {
return (
<div className="uploader">
<header className="uploader-header">
<div className="uploader-actions pull-left">
<div className="uploader-submit"></div>
<CancelButton router={this.props.router} />
</div>
<UploadButton callback={this.imageSelectedCallback} />
</header>
<Preview imageUri={this.state.imageUri} />
</div>
)
}
Couldn't I do something like the <Preview /> component? I mean, it is there, but something just appears when this.state.imageUri is different of null. This is the implementation of Preview:
var Preview = {
render: function () {
return (
<img src={this.props.imageUri} />
)
}
};
module.exports = React.createClass(Preview);
Yes, I know — "Preview" is invisible by default because it is an image, but I want to know if there's another approach to reach what I want: to show something based on a state, using the render method.
React doesn't render falsy values, be it a component or an attribute (like in the Preview case), e.g.
<div>{null}</div>
<img src={null} />
renders to
<div></div>
<img/>
So typically you just create a variable and conditionally assign it a component or null as was also suggested in another answer:
var button = null;
if(myConditionForShowingButton) {
button = <SubmitButton />;
}
-- or simply --
var button = myConditionForShowingButton ?
<SubmitButton /> :
null;
In cases where the component gets bigger it's typically more readable and cleaner to have a subroutine for rendering that part
var complexComponent = condition ?
this.renderComplexComponent() :
null
Yes. If-Else in JSX.
render: function () {
var submitButton;
if (this.state.imageSelected)
submitButton = <SubmitButton />;
return (
<div className="uploader">
<header className="uploader-header">
<div className="uploader-actions pull-left">
<div className="uploader-submit">{ submitButton }</div>
<CancelButton router={this.props.router} />
</div>
<UploadButton callback={this.imageSelectedCallback} />
</header>
<Preview imageUri={this.state.imageUri} />
</div>
)
}

Categories