Conditional getInitialState- if value null - javascript

I am having some trouble with getInitialState in react. I have some data that arrives in my props, but it will not always have the key "text".
I want it to just give it an empty value if it doesn't find the props field "text"
I basically want to say
`this.props.photo.info[0].text OR if that doesn't exist, show ''
I tried this with
The below gives an invalid props error:
getInitialState() {
return {
value: ((this.props.photo && this.props.photo.info && this.props.photo.info[0].text) || '')
This gave the same error:
value:this.props.photo.info[0].text || 'empty'
If I do the below, all that gets returned is [Object, Object] which makes me think it is returning the value from the first this.props.photo or .info (ie not all the way to info[0].text)
(this.props.photo || this.props.photo.info || this.props.photo.info[0])
This is a sample of my json data in the props
{
"title": "Item 1",
"info": [
{
"text": "<h1> I'm a real value </h1> <br/> <p> Not always here</p>",
}
],
},
{
"title": "Item 2",
"info": [],
},

I can see why your second example would be [Object Object] but the first one looks like it should work to me, but you will get an error if there is no info[0]. Try the following? -
getInitialState() {
return {
value: ((this.props.photo && this.props.photo.info && this.props.photo.info[0] && this.props.photo.info[0].text) || '')
};
}

I often use default values, they can provide default values in a very elegant way.

Related

cause of TypeError: Cannot read properties of undefined

I'm trying to fetch some data from an API. The below code "works" when I log the results to console like console.log(liveInfo.tracks), but when I try to do console.log(liveInfo.tracks.current) it fails with this error: TypeError: Cannot read properties of undefined (reading 'current'). Isn't liveInfo.tracks.current how one would normally access the key-value pair?
componentDidMount() {
fetch('https://kchungradio.airtime.pro/api/live-info-v2')
.then(res => res.json())
.then(
(result) => {
this.setState({
isLoaded: true,
liveInfo: result
})
}
)
}
The json looks more or less like this:
{
"station": {
"env": "production",
},
"tracks": {
"previous": {
"name": "a",
"metadata": {
"id": 1,
},
},
"current": {
"name": "b",
"metadata": {
"id": 2,
}
}
}
}
Because at some point liveInfo.tracks was undefined
Although there is a lack of hints, a common mistake when fetching data from lifecycle is trying to retrieve the value through the state before setData occurs.
Before you use liveInfo, make sure that data fetching is finished
like this
class SomeComponent = {
render() {
if(!this.state.liveInfo?.tracks?.current) return null
....
}
}
It looks you are trying to access to the current before it is filled on the componentDidMount, it means before the fetch has been performed. I suggest you to initialize the state like this:
state = {
isLoaded: false,
liveInfo: {
tracks: {
curent: {}
}
}
};
So you will be able to access the current property inside tracks without facing the TypeError. I made a codesandbox, so you can check an example there.
If this does not solve your problem, please let me know ;)
Your call looks right,
another way to get the value is console.log(liveInfo.tracks["current"]);
but I think your tracks has no value at runtime. Maybe you can show us more code where you are call console.log.
Maybe you run twice in your statement and at first time it is undefined and throw the error. So add a null check like this console.log(liveInfo?.tracks?.current);
Use Question mark (?)
? will check for null. If your object is null ? will handle it.
liveInfo?.tracks?.current
this is the right approach.
Further -
liveInfo?.tracks?.current?.metadata

Showing error for multiple empty inputs vuejs vuetify

I have three inputs as externalIP as External Host, externalHttpPort as Port and vendor as Vendor, I want to show error message if any of them is missing. but being specific about the name,
if (!this.externalIP || !this.externalHttpPort || !this.vendor) {
when I do if condition, this works but I am not sure how I can tell if which input is empty. only one way which left is to add 3 multiple if
something like this
let error;
error = !this.externalIP
? "External IP Address (or URL) is incorrect"
: "" || !this.externalHttpPort
? "Port is missing" : "" || !this.vendor
? "Please choose camera vendor or add your camera snapshot URL." : ""
if (!error == "") {
this.setNotification({
text: error,
color: "warning",
snackbar: true
})
return
}
is there any other way of doing it? Also, Eslint show warning on indentations as well
In this way, you can achieve the same result as by your logic without using multiple if. Also, this way will keep your template & logic clean/easily scalable.
new Vue({
el: '#app',
data: {
fields: [
{
key: 'externalIP',
value: '',
validationMessage: 'External IP Address (or URL) is incorrect'
},
{
key: 'externalHttpPort',
value: '',
validationMessage: 'Port is missing'
},
{
key: 'vendor',
value: '',
validationMessage: 'Please choose camera vendor or add your camera snapshot URL.'
}
]
},
computed: {
getError () {
let e = ''
for (let i in this.fields) {
if (!this.fields[i].value) {
e = this.fields[i].validationMessage
break
}
}
return e
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<input
v-for="(field, i) in fields"
:key="i"
v-model="fields[i].value"
/>
<br>{{ getError }}
</div>
Well, you may assign an error field variable within your error-checking condition.
Example for three variables and an emptyField variable denoting the empty variable name:
if ((!a && (emptyField = "a")) ||
(!b && (emptyField = "b")) ||
(!c && (emptyField = "c"))) {
alert("Field " + emptyField + " is empty...");
}
Since JS lazily evaluates its arguments, emptyField = "a" will get executed only if !a is true.
Just note that lazy evaluation also causes the evaluation of conditions stop once a condition was hit, thus if a is null and also b is null, the alert would announce that "Field a is empty..."
if vuetify you can use rules to check inputs
for example:
in your template:
<v-text-field
rules="[rules.required]"
/>
and in your data:
data() {
return {
rules: {
required: (value) => !!value || 'This field is required.'
}
}
},
you can add any other checking to rules array and just add it to your input by passing it to rules prop
hope it helps you!!!
I'm using VeeValidate to handle all of Validation job, maybe you will be interested in it:
https://logaretm.github.io/vee-validate/

ReactJS State OR Logical Operator always causing type error

I've got a simple state setup for a component that still throws the error: TypeError: Cannot read property 'year' of undefined with this code:
export default class Login extends Component {
state = {
isLoading: false,
events: this.props.events,
activeDate: {
year: this.props.events[0].year || "",
month: this.props.events[0].months[0].month || "",
}
};
//...
}
I'm having trouble understanding why this errors out instead of just setting the value to null. undefined should render the binary operation as false and default to "". Can anyone explain?
Instead of using year: this.props.events[0].year || "", I found that that this worked just as well, year: "" && this.props.events[0].year. The AND operator will equate to the last true value.
But, as #AlexanderStaroselsky pointed out, this isn't best practice. See this article for more details.
You can validate that the object in the array at position 0 is not null then use && before to access the property of the array object. Finally, add || to specify a default value when both conditions give null or undefined.
this.props.events[0] && this.props.events[0].year || ""

React - how to render a map of field arrays (multiple responses to a single form question)

I'm trying to figure out how to use react-hook-forms with field arrays. I have the form working (this code sandbox is where im testing changes to make this work: https://codesandbox.io/s/react-hook-form-custom-input-7cdoh), but am now trying to figure out how to render the data.
I can log a json packet as:
"ethics": {
"0": {
"explain": "df",
"managementPlan": "sdf"
},
"1": {
"explain": "sdf",
"managementPlan": ""
},
"value": "informedconsent",
"label": "Informed consent"
}
Then, in my display, I'm trying to loop through each array as follows:
{state.data.ethics.each.map(ethics => <Tag color="magenta">{ethics.label}</Tag>)}
This doesn't work - the error message says:
TypeError: Cannot read property 'map' of undefined
What do I need to do to present the output?
As mentioned earlier, you have a ethics object and not array.
object.keys(state.data.ethics).map(k=>{
const obj = state.data.ethics[key];
/* your obj will look like below
{
"explain": "df",
"managementPlan": "sdf"
}
*/
// Do Whatever you want to do with obj now
return (<>
<div>{obj.explain}</div>
<div>{obj.managementPlan}</div>
</>)
});

On/off toggle for filtering content React

This React code is filtering variables according to the "tag" which it contains (as seen in the list array).
However, I cannot toggle the filter variables (tags) on/off.
I want to be able to turn certain filters on/off, and have just those filters apply.
How is this achieved?
My entire code is in this codepen (
http://codepen.io/yarnball/pen/GqbyWr?editors=1010)
I believe I have to some how add it to the array on line 79 (below), but I have not had success with this
Line 79:
selectTag: function (tag) {
this.setState({
displayedCategories: this.state.displayedCategories.concat([tag]),
$push : [newObject]
});
},
My data looks like this:
"title": "Into the Wild",
"tag": [
{
"name": "Movie",
"taglevel": 1,
"id": 1
},
{
"name": "Adventure",
"taglevel": 2,
"id": 30
},
{
"name": "Book",
"taglevel": 1,
"id": 2
}
],
"info": []
}
In order to toggle the filters, you will need to check for the existence of the tag in the existing displayedCategories, look through the array for the tag, and then either remove it or add it in.
It is normally my preference to try to be functional so that assignment cannot cause confusion, so I will use a mostly functional style.
First to check for the presence of the tag we can use a filter operation.
var filteredCategories = this.state.displayedCategories
.filter(function (existingTag) {
return existingTag.taglevel !== tag.taglevel ||
existingTag.id !== tag.id;
});
So we now have a list of tags that are filtered to only include those that don't match the passed tag. We can check if the filtered list is the same size as the old list to see if we removed one. Alternatively, we could have filtered the other way around to see if we needed to remove one using some.
if (filteredCategories.length === this.state.displayedCategories.length){
// tag wasn't present, add it
} else {
// tag was present, use filtered list.
}
As I said above, I prefer functional, so we can do it slightly differently:
var newCategories = filteredCategories.length === this.state.displayedCategories.length ?
filteredCategories.concat([tag]) :
filteredCategories;
and then we need to set state:
this.setState({
displayedCategories: newCategories,
});
To combine those together:
var filteredCategories = this.state.displayedCategories
.filter(function (existingTag) {
return existingTag.taglevel !== tag.taglevel ||
existingTag.id !== tag.id;
});
var newCategories = filteredCategories.length === this.state.displayedCategories.length ?
filteredCategories.concat([tag]) :
filteredCategories;
this.setState({
displayedCategories: newCategories,
});

Categories