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'm looking for a way to give a user an option to define template literal. That template will be sent to backend and used with the data he provided.
Example scenario:
const dataSentToBackend = [
{
name: 'Adam',
country: 'Spain'
},{
name: 'Eve',
country: 'Germany'
}
]
User wants to generate two files that are like that: {name} from {country} (or anything else that let's him use tags how he like). So files in this example would be named as Adam from Spain and Eve from Germany.
The trick is that template needs to be preserved as a template so it can be used when data is actually being processed at the backend. So it can be used in a loop that names files one by one by the dataSentToBackend array.
So far I only found String.raw function (thanks to this page), but I didn't found it much helpful for me (or I didn't understood it).
Here's one way of doing it. I used the regular expression [a-z]+ for the property name which you could expand if you need to allow more characters (uppercase, underscores, numbers etc.)
const dataSentToBackend = [
{
name: 'Adam',
country: 'Spain'
}, {
name: 'Eve',
country: 'Germany'
}
]
const templateSentToBackend = "{name} from {country}";
serverSideReplace = (template, datas) =>
datas.map(data => template.replace(/\{([a-z]+)\}/g, (_, key) => data[key]));
console.log(serverSideReplace(templateSentToBackend, dataSentToBackend));
Assuming that your user is inputing is template string in an input field. You can simple save an escaped string in your database, and unescape the same before compiling it into template string.
And to actually use it back you can try something like this.
const templateString = "Hello ${this.name}!"; // replace it with unescaped template
const templateVars = {
name: "world"
}
const fillTemplate = function(templateString, templateVars){
return new Function("return `"+templateString +"`;").call(templateVars);
}
console.log(fillTemplate(templateString, templateVars));
But i would definitely say don't let user define templates and use it, unless you have a really solid sanitizing script.
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}
I have an Array that I use to populate a Dialog Vue Component. I have:
basicInfo: [{ firstName: "John" , lastName: "Doe" }],
<basicInfoForm v-model="showBasicInfoForm" :basicInfo="newbasicInfo[0]"></basicInfoForm>
on the Parent I have
{{basicInfo[0].firstName + ' ' + basicInfo[0].lastName}}
I have a button that will call a Form Component and open a Dialog popup that allows editing. My problem is that all changes to the Dialog are also immediately shown on the Parent. I would like to have on the Child Dialog a cancel button so no changes will be made. I cloned the array before I pass it:
this.newbasicInfo = this.basicInfo.slice();
and on the Child Dialog
<v-text-field
v-model="basicInfo.firstName"
label="First Name"
class="input-name styled-input"
></v-text-field>
props: {
value: Boolean,
basicInfo: Array
},
My problem is that I can see each key stroke as changes are being made so there is no way to go back to the original if a cancel is selected. I'm new to Vue and Components so I could have something totally screwed up. Why are changes being make to both the basicInfo array and the newbasicInfo array at the same time.
What is happening here is that you are copying the array by reference. So when you modify the index of one array, actually both are modified because they share the same reference.
What you need to do is to copy the array by values.
this can be easily done this way : this.newbasicInfo = JSON.parse(JSON.stringify(this.basicInfo));
You can check this question on SO for more context : How do you clone an Array of Objects in Javascript?
Your clone method does not work with an array of objects:
const basicInfo = [{ firstName: "John" , lastName: "Doe" }]
const newbasicInfo = basicInfo.slice()
This method creates a "shallow copy" - that means it works with numbers, strings, etc. but does not really create a clone of objects. The cloned objects this way keep their reference, so they will actually be the "same" objects as in the source array.
const basicInfo = [{ firstName: "John" , lastName: "Doe" }]
const newbasicInfo = JSON.parse(JSON.stringify(basicInfo))
This method creates a "deep copy" - everything it holds will be cloned, no matter how "deep" they are nested.
If you have an array of simple values, the shallow copy is more efficient, but if you have objects in your array you need deep copy.
So, it's not a Vue problem, but a more general JavaScript question.
Here's a little snippet, to illustrate the difference:
const basicInfo1 = [{
firstName: "John",
lastName: "Doe"
}]
const newbasicInfo1 = basicInfo1.slice()
newbasicInfo1[0].firstName = "Johnnyboy"
console.log('basicInfo1: ', basicInfo1)
console.log('newbasicInfo1: ', newbasicInfo1)
const basicInfo2 = [{
firstName: "John",
lastName: "Doe"
}]
const newbasicInfo2 = JSON.parse(JSON.stringify(basicInfo2))
newbasicInfo2[0].firstName = "Johnnyboy"
console.log('basicInfo2: ', basicInfo2)
console.log('newbasicInfo2: ', newbasicInfo2)
A String contains list of Objects which are serialized in JSON format, how to convert that to list of JSON Objects like given in example below preferably without using jQuery.
Eval, Stringyfy Json.parse etc dont seems to help here.
[
{firstName: 'Laurent', lastName: 'Renard', birthDate: new Date('1987-05-21'), balance: 102, email: 'whatever#gmail.com'},
{firstName: 'Blandine', lastName: 'Faivre', birthDate: new Date('1987-04-25'), balance: -2323.22, email: 'oufblandou#gmail.com'},
{firstName: 'Francoise', lastName: 'Frere', birthDate: new Date('1955-08-27'), balance: 42343, email: 'raymondef#gmail.com'}
];
Update:- JSON String
[
{"attributes":{"type":"Contact","url":"/services/data/v30.0/sobjects/Contact/0039000000wvt6yAAA"},"Name":"Stella Pavlova","Phone":"(212) 842-5500","CreatedDate":"2014-05-15T06:17:48.000+0000","Id":"0039000000wvt6yAAA"},
{"attributes":{"type":"Contact","url":"/services/data/v30.0/sobjects/Contact/0039000000wvt6zAAA"},"Name":"Lauren Boyle","Phone":"(212) 842-5500","CreatedDate":"2014-05-15T06:17:48.000+0000","Id":"0039000000wvt6zAAA"},
{"attributes":{"type":"Contact","url":"/services/data/v30.0/sobjects/Contact/0039000000wvt70AAA"},"Name":"Babara Levy","Phone":"(503) 421-7800","CreatedDate":"2014-05-15T06:17:48.000+0000","Id":"0039000000wvt70AAA"},
{"attributes":{"type":"Contact","url":"/services/data/v30.0/sobjects/Contact/0039000000wvt71AAA"},"Name":"Josh Davis","Phone":"(503) 421-7800","CreatedDate":"2014-05-15T06:17:48.000+0000","Id":"0039000000wvt71AAA"},
{"attributes":{"type":"Contact","url":"/services/data/v30.0/sobjects/Contact/0039000000wvt72AAA"},"Name":"Jane Grey","Phone":"(520) 773-9050","CreatedDate":"2014-05-15T06:17:48.000+0000","Id":"0039000000wvt72AAA"},
{"attributes":{"type":"Contact","url":"/services/data/v30.0/sobjects/Contact/0039000000wvt73AAA"},"Name":"Arthur Song","Phone":"(212) 842-5500","CreatedDate":"2014-05-15T06:17:48.000+0000","Id":"0039000000wvt73AAA"},
{"attributes":{"type":"Contact","url":"/services/data/v30.0/sobjects/Contact/0039000000wvt74AAA"},"Name":"Ashley James","Phone":"+44 191 4956203","CreatedDate":"2014-05-15T06:17:48.000+0000","Id":"0039000000wvt74AAA"},
{"attributes":{"type":"Contact","url":"/services/data/v30.0/sobjects/Contact/0039000000wvt75AAA"},"Name":"Tom Ripley","Phone":"(650) 450-8810","CreatedDate":"2014-05-15T06:17:48.000+0000","Id":"0039000000wvt75AAA"},
{"attributes":{"type":"Contact","url":"/services/data/v30.0/sobjects/Contact/0039000000wvt76AAA"},"Name":"Liz D'Cruz","Phone":"(650) 450-8810","CreatedDate":"2014-05-15T06:17:48.000+0000","Id":"0039000000wvt76AAA"},
{"attributes":{"type":"Contact","url":"/services/data/v30.0/sobjects/Contact/0039000000wvt77AAA"},"Name":"Edna Frank","Phone":"(650) 867-3450","CreatedDate":"2014-05-15T06:17:48.000+0000","Id":"0039000000wvt77AAA"},
{"attributes":{"type":"Contact","url":"/services/data/v30.0/sobjects/Contact/0039000000wvt78AAA"},"Name":"Avi Green","Phone":"(212) 842-5500","CreatedDate":"2014-05-15T06:17:48.000+0000","Id":"0039000000wvt78AAA"},
{"attributes":{"type":"Contact","url":"/services/data/v30.0/sobjects/Contact/0039000000wvt79AAA"},"Name":"Siddartha Nedaerk","CreatedDate":"2014-05-15T06:17:48.000+0000","Id":"0039000000wvt79AAA"},
{"attributes":{"type":"Contact","url":"/services/data/v30.0/sobjects/Contact/0039000000wvt7AAAQ"},"Name":"Jake Llorrac","CreatedDate":"2014-05-15T06:17:48.000+0000","Id":"0039000000wvt7AAAQ"},
{"attributes":{"type":"Contact","url":"/services/data/v30.0/sobjects/Contact/0039000000wvt6rAAA"},"Name":"Rose Gonzalez","Phone":"(512) 757-6000","CreatedDate":"2014-05-15T06:17:48.000+0000","Id":"0039000000wvt6rAAA"},
{"attributes":{"type":"Contact","url":"/services/data/v30.0/sobjects/Contact/0039000000wvt6sAAA"},"Name":"Sean Forbes","Phone":"(512) 757-6000","CreatedDate":"2014-05-15T06:17:48.000+0000","Id":"0039000000wvt6sAAA"},
{"attributes":{"type":"Contact","url":"/services/data/v30.0/sobjects/Contact/0039000000wvt6tAAA"},"Name":"Jack Rogers","Phone":"(336) 222-7000","CreatedDate":"2014-05-15T06:17:48.000+0000","Id":"0039000000wvt6tAAA"},
{"attributes":{"type":"Contact","url":"/services/data/v30.0/sobjects/Contact/0039000000wvt6uAAA"},"Name":"Pat Stumuller","Phone":"(014) 427-4427","CreatedDate":"2014-05-15T06:17:48.000+0000","Id":"0039000000wvt6uAAA"},
{"attributes":{"type":"Contact","url":"/services/data/v30.0/sobjects/Contact/0039000000wvt6vAAA"},"Name":"Andy Young","Phone":"(785) 241-6200","CreatedDate":"2014-05-15T06:17:48.000+0000","Id":"0039000000wvt6vAAA"},
{"attributes":{"type":"Contact","url":"/services/data/v30.0/sobjects/Contact/0039000000wvt6wAAA"},"Name":"Tim Barr","Phone":"(312) 596-1000","CreatedDate":"2014-05-15T06:17:48.000+0000","Id":"0039000000wvt6wAAA"},
{"attributes":{"type":"Contact","url":"/services/data/v30.0/sobjects/Contact/0039000000wvt6xAAA"},"Name":"John Bond","Phone":"(312) 596-1000","CreatedDate":"2014-05-15T06:17:48.000+0000","Id":"0039000000wvt6xAAA"}
]
I edited your post to make it more visibly clear, so maybe now you'll see: The value you posted as your "JSON String" is actually a JavaScript array of objects; exactly what you're claiming you're trying to convert the string into. You should read up more on JSON so you fully understand how you can convert to and from JSON, but that's already a valid JavaScript object -- you don't need to do anything to it.
Here's a JSFiddle showing this fact in action -- all you need to do is set a variable equal to the block of code you're receiving, and you can access it as a normal array/object. http://jsfiddle.net/ZpXVh/
var array = /* your really long code */;
alert(array[1]['name'];