I have state:
{
studentId: 1,
studentName: "Student",
religion: {
religionId: 1,
religionName: "RELIGION"
}
}
How to access religionName in react?
I have tried access my student state like this:
const {studentState} = useContext(StudentContext);
return (
<div>
{studentState.studentId}
{studentState.studentName}
{studentState.religion.religionName}
</div>
);
Undifined result when using {studentState.religion.religionName}
Although it is hard to tell without a minimal reproducible example, one thing that stands out is the use of the curly braces around {studentState}.
If the object in the example you provided is the entire context value, you should not use curly braces, because this would try to extract a property called studentState from the context object, which does not exist in your example. Instead, you just want the entire context value:
const studentState = useContext(StudentContext);
This assumes you have previously created your StudentContext object somewhere and provided a value, something like this:
const StudentContext = React.createContext(null);
// Later, define a value
const studentState = {
studentId: 1,
studentName: "Student",
religion: {
religionId: 1,
religionName: "RELIGION"
}
};
// Then in a component, render the context provider:
<StudentContext.Provider value={studentState}>
...
</StudentContext.Provider>
Read up on object destructuring in JavaScript (this is a good intro). That is what the curly braces you are using are doing.
You must use condition for handling this situation..
Try this one
{ studentState.religion && studentState.religion.religionName}
Related
I have a read-only object that is returned by GraphQL (vue-apollo) query, the result which is read-only looks something like this:
result: {
id: 'yh383hjjf',
regulations: [{ title: 'Test', approved: false}]
})
I want to bind this to a form and be able to edit/update the values in the regulations array and save it back to the database.
at the moment when I try to edit I get the error below:
Uncaught TypeError: "title" is read-only
I tried cloning the result returned by the database using object.assign
//target template
const regulatoryApprovals = {
id: null,
regulations: [{ title: null, approved: null}]
})
regulatoryApprovals = Object.assign(regulatoryApprovals, result, {
regulations: Object.assign(regulatoryApprovals.regulations, result.regulations)
})
but this didn't work.
Does anyone know how I can properly clone the result?
regulatoryApprovals= Object.assign(regulatoryApprovals, ... indicates the problem because regulatoryApprovals is modified with Object.assign, so it would need no assignment.
Read-only regulatoryApprovals object needs to be cloned. regulations is an array and won't be merged correctly with Object.assign, unless it's known that array elements need to be replaced. It should be:
regulatoryApprovals = {
...regulatoryApprovals,
...result,
regulations: [...regulatoryApprovals.regulations, result.regulations]
}
Where { ...regulatoryApprovals, ... } is a shortcut for Object.assign({}, regulatoryApprovals, ...).
I want to create rootStore which contains others store. The problem is that the children contain properties like:
id: types.identifier(types.string),
And when I create the rootStore, I get an error from the child:
[mobx-state-tree] Error while converting {} to SomeModelStore: at path "/id" value undefined is not assignable to type: identifier(string) (Value is not a string), expected an instance of identifier(string) or a snapshot like identifier(string) instead.
I tried to use types.late but it did not help.
The solution I found is to wrap all properties into types.maybe
Examples:
error:
https://codesandbox.io/s/yvnznxyvyj?module=%2Fmodels%2FSomeModelStore.js
workaround:
https://codesandbox.io/s/0mv558yq50?module=%2Fmodels%2FSomeModelStore.js
Here https://codesandbox.io/s/yvnznxyvyj?module=%2Fmodels%2FSomeModelStore.js you create an empty object
.model("FirstStore", {
item: types.optional(SomeModelStore, {})
})
but type
SomeModelStore
didn't support empty fields. If you write like this
export const FirstStore = types
.model("FirstStore", {
item: types.optional(SomeModelStore, {
id: 'defaultId',
activate: false,
name: 'defaultName'
})
})
it will work. Or you can use "types.maybe" instead of "types.optional".
export const FirstStore = types
.model("FirstStore", {item: types.maybe(SomeModelStore)})
Also read about types.reference
I think it's a better way to use it in your case.
In a Vue Js component, I need to loop through an object on the mounted hook that's in local storage in Vuex to update the data properties as you can see in code example.
I'm trying to update this.title, this.body, this.id whereby the rightHere variable in the loop is outputting these names as string values as the var you can see.
this.rightHere
...is the problem I know, and is obviously trying to target a data property "rightHere" which doesn't exist. But I don't know how else to overcome this in javascript and make rightHere output the string as needed? So how do I use this in a loop to dynamically change but tell Vue to update this. on each iteration?
data() {
return {
title: '',
body: '',
id: '',
}
},
mounted() {
for (var rightHere in this.$store.getters.getObject) {
if (this.$store.getters.getObject.hasOwnProperty(rightHere )) {
this.rightHere = this.$store.getters.getObject[rightHere ]
}
}
},
You would typically set the key in your template. It's a reserved word.
<div v-for='item in items' :key='$store.getters.getKey(item)'>{{item.title}}</div>
I am using firebase, and angularfire.
there are so many ways to do CRUD with the Firebase Api
actually, I still don't get what is specific difference for using
$add with $firebaseArray
.push() method
.set() method
I think they are technically same, I prefer to use .set method() without knowing the exact reason, why I'd using that. is there any specific reason to not use it? what is exactly $firebaseArray did? if we could just declare basic reference variable.
in this case:
var usersRef = Ref.child('users');
$scope.createUser = function() {
$scope.userRef.child($id).set({
name: name
});
};
or
$scope.data = $firebaseArray(Ref.child('users'));
$scope.createUser = function() {
$scope.data.child($id).$add({
name: name
});
};
thank you.
If I have the following data tree in Firebase:
{
users:
{
key: { name:"bob" }
}
}
When I do an $add, I will create a new item in the tree
$scope.data.child('users').$add({
name: name
});
Since $add uses the Push method in Firebase, new random Key will be used when pushing data to the child.
{
users:
{[
key: { name:"bob" },
key2: { name:"name" }
]}
}
If I do a set on the same Users object, I will overwrite the data that is already there. So, in your example, without specifying a key, you will overwrite the entire user object.
$scope.userRef.child('users').set({
name: name
});
};
This will result with this data
{
users:
{
name: "name"
}
}
This happens because any null values you pass to the Set method will delete any data that was originally there.
Passing null to set() will remove the data at the specified location.
https://www.firebase.com/docs/web/api/firebase/set.html
What I am trying to do is to get data from the server and then putting it all in an observable and then make all the properties observable. The issue I am facing is that it does not make all my properties observable and I need them all to be observable as sometimes depending on the data it makes some properties observable and sometimes it doesn't.
var viewModel = this;
viewModel.Model = ko.observable();
viewModel.SetModel = function (data) {
viewModel.Model(ko.mapping.fromJS(data));
}
The data that I am receiving from the server is like this for example: normaldata,items(this is an array with unknown number of elements).
so if i try to access data like viewModel.Model().Items[0]().Layer() i sometimes have Layer as a function and sometimes it is a normal element with observable elements.I want all my objects inside Items to have Layer as a function.
Server data example:
Name: "test"
Items: [Layer[ID: 132]]
In this example Name,Items and ID are observable but Layer is not.
Fiddle example:
jsfiddle.net/98dv11yz/3
So the problem is that sometimes the layer is null resulting in ko making the property observable but sometimes that property has id and ko makes only the child elements observable. The problem is that i have if's in the code and i want it to be a function so i can always reffer to it as layer() because now it is sometimes layer or layer()
An explenation for what's happening:
When the ko.mapping plugin encounters an object in your input, it will make the object's properties observable, not the property itself.
For example:
var myVM = ko.mapping.fromJS({
name: "Foo",
myObject: {
bar: "Baz"
}
});
Will boil down to:
var myVM = {
name: ko.observable("Foo"),
myObject: {
bar: ko.observable("Baz")
}
}
and not to:
var myVM = {
name: ko.observable("Foo"),
myObject: ko.observable({
bar: ko.observable("Baz")
})
}
The issue with your data structure is that myObject will sometimes be null, and sometimes be an object. The first will be treated just as the name property in this example, the latter will be treated as the myObject prop.
My suggestion:
Firstly: I'd suggest to only use the ko.mapping.fromJS method if you have a well documented and uniform data structure, and not on large data sets that have many levels and complexity. Sometimes, it's easier to create slim viewmodels that have their own mapping logic in their constructor.
If you do not wish to alter your data structure and want to keep using ko.mapping, this part will have to be changed client-side:
Items: [
{ layer: {id: "0.2"} },
{ layer: null}
]
You'll have to decide what you want to achieve. Should the viewmodel strip out the item with a null layer? Or do you want to render it and be able to update it? Here's an example of how to "correct" your data before creating a view model:
var serverData = {
Name: "Example Name",
Id: "0",
Items: [
{layer: {id: "0.2"} },
{layer: null}
]
};
var correctedData = (function() {
var copy = JSON.parse(JSON.stringify(serverData));
// If you want to be able to render the null item:
copy.Items = copy.Items.map(function(item) {
return item.layer ? item : { layer: { id: "unknown" } };
});
// If you don't want it in there:
copy.Items = copy.Items.filter(function(item) {
return item.layer;
});
return copy;
}());
Whether this solution is acceptable kind of relies on how much more complicated your real-life use will be. If there's more complexity and interactivity to the data, I'd suggest mapping the items to their own viewmodels that deal with missing properties and what not...