React Javascript render error - javascript

I am currently working on my webapp and in one of its components I am getting some DB data with :
var SelectHund = React.createClass({
getInitialState: function() {
return {
hunde:{}
};
},
componentDidMount: function(){
var that = this;
$.ajax({
type: "POST",
url: "/foodoo/index.php?method=getDogs",
data: JSON.stringify(planData),
success: function(response){
var hunde = JSON.parse(response);
console.log(hunde);
if(hunde.length >= 1){
that.setState({
hunde: hunde
});
}
},
error: function(){
}
});
},
render: function(){
if(this.state.hunde.length <= 0){
return(<div>test</div>);
}else{
// console.log(this.state);
// console.log(this.state.hunde);
var POS = this.state.hunde.map(function(i){
console.log(i);
return <option key={i.id} value={i.weight}>i.name</option>;
});
return(<select className="selectHund" name="hund">{POS}</select>);
}
}
});
The component gets called like this:
return (
<div>
<h2>{this.state.planname}<span className="close">x</span></h2>
<SelectHund changeHund={this.changeHund} />
...
With that method I run through the response object with the map function, the console.log of "i" returns the single objects like following :
Object {id: "1", user_id: "1", name: "Balou", weight: "15", activity: "1"…}
Object {id: "2", user_id: "1", name: "Franzi", weight: "70", activity: "1"…}
So I guess there is no error with the object handling.
Unfortunately I keep getting this error in the console :
Uncaught Error: Invariant Violation: SelectHund.render(): A valid ReactComponent must be returned. You may have returned undefined, an array or some other invalid object.
I have tried calling an external function outside of the ajax function to see if this may cause the error but it doesn't. Some other amateur tries to debug it failed as well - So I need your help ^^

Your render method does not return anything. You need to move this line:
return(<select onChange={that.props.changeHund} className="selectHund" name="hund">{POS}</select>);
to outside the success callback. Then you will be facing other problems, but it’s in the right direction.
Instead of doing Ajax inside the render function, move it to another lifecycle method (like componentDidMount) or a data model like Flux.
Then use states or props to handle internal component data (in your example, the hunde object). Following some examples from the docs/tutorials should get you started.

Related

Vue JS 2 data manipulation

I have an instance of mounted in Vue, where I'm trying to set a date picker having the starting date depends on a data fed by an ajax response. Let's say this data property is named start_date. I run my ajax request via the created instance in Vue.
It's a little weird when I tried to console log vm.myObject, it shows the correct value start_date property coming from the ajax response. However, whenever I access the specific property via vm.myObject.start_date it will show you the default one I've created for data binding. My code structure below:
<script>
export default {
mounted() {
const vm = this;
console.log(vm.myObject); // this will show the data from ajax response
console.log(vm.myObject.start_date); //this will show the default value I set which si the 2017-10-25
},
created() {
const self = this;
$.ajax({
url: ApiRoutes.paths.GetDealData,
data: { id: 1 },
success: function(res) {
self.myObject.start_date = res.start_date;
}
});
},
data() {
return {
myObject: { start_date: "2017-10-25" }
};
}
};
</script>
I'm very new to Vue JS, so I'm currently having a hard time handling the data in the component via ajax request. I've already tried all the instances included beforeCreate, beforeMount but it didn't fix my issue still. How can I understand this kind of behavior?
Your code can't really work the way you described in your answer.
you are doing asynchronous operation (ajax call) and try to print the values right after synchronous operation? nope.
If you want to console.log(response) , you can do it in your callback function.
If you want to print the value on the page, but show nothing until the value is fetched (asynchronous operation), you can define on your data an attribute that signal if the fectching process is finished or not. and toggle it inside your callback.
I have edited the code to show how to declare the date-picker (have to be declared from the template side.
You have to pass the start_date as a props (I assume the prop name for the date-picker is start-date). when the ajax request is finished, the reactivity of vue will take care of re-rendering of the date-picker
<template>
<div>
<datePicker :start-date="myObject.start_date" />
</div>
</template>
<script>
export default {
created() {
$.ajax({
url: ApiRoutes.paths.GetDealData,
data: { id: 1 },
success: function(res) {
self.myObject.start_date = res.start_date;
self.isFetchedFinished = true
}
});
},
data() {
return {
startDate: ''
};
}
};
</script>
The reason is console.log() working before AJAX response is returned, so console.log(vm.myObject.start_date) prints unchanging string with initial value. However, console.log(vm.myObject) prints your object, which then changes, and you can see actual property value in browser console.
Example:
var obj = { "name": "oldName" };
console.log(obj);
obj.name = "newName";
If you want a "frozen" version of your object, you can create a copy for logging:
console.log(Object.assign({}, vm.myObject));
Also, instead self.myObject.start_date = res.start_date; you probably want to use this.$set(this.myObject, 'start_date', res.start_date); for change tracking.

Using React to call Nested API?

Say I had the following JSON file:
{
"farmer": [
{
"crops": "corn"
}
],
"activities":{
"hobbies": "swimming"
},
"name: Todd"
}
I would like to know how to make calls to them using React. My best attempt is as shown below.
componentDidMount: function(){
var selfish = this;
$.get('~~someurl~~', function(data){
selfish.setState(data);
});
},
render: function(){
return (<div>
<p>{this.state.name}</p>
<p>{this.state.activities.hobbies}</p>
<p>{this.state.farmer[0].crops}</p>
</div>)
}
I get that the first one {this.state.name} will run as it has been written. However, I am uncertain as to how to express the final two {this.state.activities.hobbies} and {this.state.farmer[0].crops} using the React syntax.
I have written them out in hopefully a way that expresses what I am trying to achieve with each call.
EDIT: The specific error that results from the latter two state that they are undefined.
EDIT: So I got the second one working by adding an empty initial state.
getInitialState: function(){
return {activities: '', farmer: ''}
}
However, this leaves the last one, which still returns an error.
The problem is that you are using componentDidMount when you should use componentWillMount. Check out the documentation on these lifecycle methods.
This is what the documentation says about componentDidMount
Invoked once, only on the client (not on the server), immediately
after the initial rendering occurs.
Which means when you first render your states are not declared unless you have used getInitialState before (another lifecycle method).
I simply did this:
componentWillMount: function () {
this.setState({
"farmer": [
{
"crops": "corn"
}
],
"activities":{
"hobbies": "swimming"
},
"name": "Todd"
});
},
and I was able to use this.state.farmer[0].crops in my render method
EDIT:
To be clear. If you need to retrieve the data after you rendered the component then you need to specify default values for the states that you use in render. This can be achieved using getInitialState:
getInitialState: function () {
return {
"farmer": [
{
"crops": DEFAULT_VALUE
}
],
"activities":{
"hobbies": DEFAULT_VALUE
},
"name": DEFAULT_VALUE
});
},

Object's data missing when passing to Meteor.call

In my React/Meteor application, I am trying to pass an object with data from the state to a method on the server, for insertion into the database. However, there seems to be an issue passing the object from the React component to the Meteor method - one of the child objects ends up in the Meteor method, but all of its children are gone. I do nothing to the object except use check() to ensure it is an Object:
'Appointments.saveData'(dataObj) {
check(dataObj, Object);
console.log(dataObj);
// ....
}
Here's what happens on the front-end:
Meteor.call('Appointments.saveData', {
vitalsData: this.state.vitalsData || {},
subjectiveData: this.state.subjectiveData || '',
physicalExamData: this.state.physicalExamData || {},
rosData: this.state.rosData || {},
impressionData: this.state.impressionData || [],
extraNotes: this.state.extraNotes || ''
}, (err, res) => {
if (res && !err) {
this.refs.toasts.success(
'Data for this encounter has been saved.',
'Records saved!'
);
} else {
this.refs.toasts.error(
'An unknown error has occurred. Reload the page and try again.',
'Error!'
);
}
});
I combine all of my state variables into an object using {}, which in turn becomes dataObj in the method. However, dataObj.impressionData exists, and is an array containing objects, however, data is missing from any of the objects in the array.
For example, dataObj.impressionData[0].diagnosis should be an object, in fact, it is supposed to be an exact copy of an object already pulled from the database. However, if I console.log it, the object is empty.
I have verified that the data exists as it should at each step before passing to the Meteor method. I console.log the object immediately before calling Meteor.call and immediately after calling check in my method. I cannot for the life of me understand why data is missing.
What am I forgetting?
EDIT: I've changed my code so that the data is now added to the state directly from a ref. Now the server method does properly receive the object. However, in the following code:
if (dataObj.impressionData && dataObj.impressionData.length > 0) {
dataObj.impressionData.forEach(obj => {
console.log(obj); // obj.diagnosis exists and is as expected
const x = ICD10Codes.findOne({ _id: obj.diagnosis._id });
console.log(x); // this also works as it should
impressionFields.push({ patientId: appt.patient._id, diagnosis: x, note: obj.note, x });
});
}
Setting diagnosis to x, which I KNOW is a valid copy of the object straight from the database yields the same results:
meteor:PRIMARY> db.EncounterData.findOne()
...
"impression" : {
"patientId" : "47de32b428d8c4aaac284af3",
"appointmentId" : "TwL7DF9FoXPRgmrjR",
"fields" : [
{
"patientId" : "47de32b428d8c4aaac284af3",
"diagnosis" : {
}
}
]
},
...
I think I'm going crazy.
So your issue comes down to the fact that this.setState is an asynchronous function, so when you make your Meteor call, this.state hasn't actually be updated yet. As such, you need to wait for the this.setState call to finish. The only way to do this is to use the React lifecycle methods. You can use either componentWillUpdate (called before the next render) or componentDidUpdate (called after the next render).
var MyComponent = React.createClass({
save: function() {
...
case 'impression':
this.setState({ impressionData: data }, this.callServerMetho‌​d);
break;
...
},
// This is one of the React lifecycle methods
componentWillUpdate: function(nextProps, nextState) {
// Put your Meteor call here
// Make sure to use nextState instead of this.state
// This way you know that this.state has finished updating
}
});
I solved the issue myself - it turns out that I was importing my SimpleSchema objects as default but exporting my SimpleSchema objects as named. The SimpleSchema objects were thus invalid.

Cannot get response content in mithril

I've been trying to make a request to a NodeJS API. For the client, I am using the Mithril framework. I used their first example to make the request and obtain data:
var Model = {
getAll: function() {
return m.request({method: "GET", url: "http://localhost:3000/store/all"});
}
};
var Component = {
controller: function() {
var stores = Model.getAll();
alert(stores); // The alert box shows exactly this: function (){return arguments.length&&(a=arguments[0]),a}
alert(stores()); // Alert box: undefined
},
view: function(controller) {
...
}
};
After running this I noticed through Chrome Developer Tools that the API is responding correctly with the following:
[{"name":"Mike"},{"name":"Zeza"}]
I can't find a way to obtain this data into the controller. They mentioned that using this method, the var may hold undefined until the request is completed, so I followed the next example by adding:
var stores = m.prop([]);
Before the model and changing the request to:
return m.request({method: "GET", url: "http://localhost:3000/store/all"}).then(stores);
I might be doing something wrong because I get the same result.
The objective is to get the data from the response and send it to the view to iterate.
Explanation:
m.request is a function, m.request.then() too, that is why "store" value is:
"function (){return arguments.length&&(a=arguments[0]),a}"
"stores()" is undefined, because you do an async ajax request, so you cannot get the result immediately, need to wait a bit. If you try to run "stores()" after some delay, your data will be there. That is why you basically need promises("then" feature). Function that is passed as a parameter of "then(param)" is executed when response is ready.
Working sample:
You can start playing with this sample, and implement what you need:
var Model = {
getAll: function() {
return m.request({method: "GET", url: "http://www.w3schools.com/angular/customers.php"});
}
};
var Component = {
controller: function() {
var records = Model.getAll();
return {
records: records
}
},
view: function(ctrl) {
return m("div", [
ctrl.records().records.map(function(record) {
return m("div", record.Name);
})
]);
}
};
m.mount(document.body, Component);
If you have more questions, feel free to ask here.

backbone success event not called

Code
MyClass = Backbone.Model.extend({
url: '/apiurl/'+sessionValue+'',
defaults: {
data1: '',
data2: 1
}
});
var myobj = new MyClass ();
var myobjvalue = {
data1: "myvalue"
};
myobj.save(myobjvalue , {
success: function (myobj , response) {
alert("success");
},
error : function (myobj , response) {
var data = JSON.stringify(response);
console.log(data);
}
})
in the above code, save function successfully calls the REST api. (200 OK). However even after that it enters in error block.
value printed in console
{"readyState":4,"responseText":"Success","status":200,"statusText":"OK"}
What should I be doing?
===================================
What worked
Instead of string, I had to return actual object as part of REST API. apprently, backbone expects class object along with HTTP status. so responseText contained full myobj.
What worked
Instead of string, I had to return actual object as part of REST API. apprently, backbone expects class object along with HTTP status. so responseText contained full myobj.

Categories