undefined object in reactjs application - javascript

I have a container that holds search bar inside a form element consisting of two inputs, from and to, and a button.
On my form submit function, I create an OBJECT called query and it equals to:
const query = {
from : this.state.from,
to : this.state.to
};
then I pass this query object as an argument to an action that have created :
this.props.fetchPlaces(query);
In my action.js inside my fetchPlaces I have :
var skypicker = {
flyFrom : query.flyFrom,
flyTo : query.toCity,
};
I want to be able to pass flyFrom and flyTo to an api that later returns flights from flyFrom to flyTo which return results as JSON!
ofcourse i have to parse them to the URl, but at the current state flyFrom and flyTo are undefined, Am I doing this currectly?

You're accessing properties that you haven't set. The names differ between query and skypicker.
Try creating skypicker like this:
var skypicker = {
flyFrom: query.from,
flyTo: query.to
};

It’s query.from and query.to but not query.flyFrom and query.toCity
Check right one below
var skypicker = {
flyFrom : query.from,
flyTo : query.to
};
I generally do this
request body:
let data = {};
data.firstName = this.state.firstName;
data.lastName = this.state.lastName;
data.email = this.state.email;
data.password = this.state.password;
data.sex = this.state.sex;
this.props.registerUser(data);
action call:
export function registerUser(data) {
return dispatch => {
dispatch(registerUserRequest());
return ajax.post(URL_PREFIX + '/auth/register/', data)
.then(res => {
dispatch(registerUserSuccess(res.data))
setTimeout(function(){
dispatch(push('/login'))
}, 2000)
})
.catch(errors => {
dispatch(registerUserError(errors))
})
}
}

Related

Object element returning undefined with addEventListener

I am making a simple form which requests the user to input their project name and their name, along with some other info.
But each type of project has a different page, so to avoid copying and pasting the same getElementById and addEventListener functions in each page, I've made a module with those functions so every page handles it as needed. This is one of the pages:
// (imports)...
let project = {
author: null,
name: null,
mission: {
file: null,
path: null,
},
sd: {
code: null,
path: null,
},
modloaderfolder: null,
};
window.addEventListener("DOMContentLoaded", () => {
project.mission = handleMission();
project.sd = handleSD();
project.modloaderfolder = handleModloader();
project.name = handleName();
project.author = handleAuthor();
// ...
The problem is that the objects' elements are returning undefined in the two following functions:
export function handleName() {
const project = {};
const txt_name = document.getElementById("name");
txt_name.addEventListener("change", () => {
project.name = txt_name.value;
});
return project.name;
}
export function handleAuthor() {
const project = {};
const txt_author = document.getElementById("author");
txt_author.addEventListener("change", () => {
project.author = txt_author.value;
});
return project.author;
}
// Returns undefined
Whats intriguing for me is that some other functions are working as intended, I can't find out why. These are the corretly working functions:
export function handleSD() {
const project = { sd: {} };
const input_sd = document.getElementById("sd");
input_sd.addEventListener("change", () => {
document.getElementById("sel-sd").innerHTML = "";
Array.from(input_sd.files).forEach((file) => {
document
.getElementById("sel-sd")
.insertAdjacentHTML("beforeend", `<option>${file.name}</option>`);
});
if (!input_sd.files[0]) return;
const path = input_sd.files[0].path;
project.sd.path = path.substring(0, path.lastIndexOf("\\")) + "\\";
project.sd.code = project.sd.path.substring(
project.sd.path.lastIndexOf("\\") - 5,
project.sd.path.length - 1
);
});
return project.sd;
}
// This function correctly returns "sd: { path: ..., code: ...}"
What I noticed is that by returning an object, it returns and updates correctly for each change, but while returning an object's element, it aways returns undefined.
which is empty and nothing will change it because copying a primitive value is by value but the object that holds the key of the string, and as soon as the onchange function is activated it changes the value of your key in the object and it automatically changes in your object too because it is copied by Reference.
You can read more about this topic here

How to clear fields after callback from axios?

I have modal component with form. I want to inform fields of this form that form data was successfully sent to database and clear its fields.
Component code:
//ItemModal.js
addItem(e) {
e.preventDefault();
const item = {
id: this.props.itemsStore.length + 1,
image: this.fileInput.files[0] || 'http://via.placeholder.com/350x150',
tags: this.tagInput.value,
place: this.placeInput.value,
details: this.detailsInput.value
}
console.log('addded', item);
this.props.onAddItem(item);
this.fileInput.value = '';
this.tagInput.value = '';
this.placeInput.value = '';
this.detailsInput.value = '';
this.setState({
filled: {
...this.state.filled,
place: false,
tags: false
},
loadingText: 'Loading...'
});
}
...
render() {
return (
<div className="text-center" >
<div className={"text-center form-notification " + ((this.state.loadingText) ? 'form-notification__active' : '' )}>
{(this.state.loadingText) ? ((this.props.loadingState === true) ? 'Item added' : this.state.loadingText) : '' }
</div>
)
}
action.js
export function onAddItem(item) {
axios.post('http://localhost:3001/api/items/', item )
.then(res => {
dispatch({type:"ADD_ITEM", item});
dispatch({type:"ITEM_LOADED", status: true});
})
}
helper.js
else if (action.type === 'ITEM_LOADED') {
const status = action.status;
return {
...state,
isItemLoaded: status
}
}
Currently I have few issues with my code:
1. field are clearing right after click, but they should clear after changing state of loadingState. I tried to check it in separate function on in componentWillReceiveProps whether state is changed and it worked, but I faces another problem, that after closing this modal there were errors, that such fields doesn't exist.
2. loadingText should become '' (empty) after few seconds. Tried same approach with separate function and componentWillReceiveProps as at first issue.
In constructor keep a copy of your initial state in a const as follows:
const stateCopy = Object.create(this.state);
When your ajax request completes, in the sucess callback you can reset the state with this copy as follows:
this.setStae({
...stateCopy
});
One of the few ways to achieve this is to use async await which will resolve the promises and then return the value after that you can clear the values
1st approach using the async await
Here is the example
handleSubmit = async event => {
event.preventDefault();
// Promise is resolved and value is inside of the response const.
const response = await API.delete(`users/${this.state.id}`);
//dispatch your reducers
};
Now in your react component call it
PostData() {
const res = await handleSubmit();
//empty your model and values
}
Second approach is to use the timer to check the value is changed or not
for this we need one variable add this to the service
let timerFinished=false;
one function to check it is changed or not
CheckTimers = () => {
setTimeout(() => {
if (timerFinished) {
//empty your modal and clear the values
} else {
this.CheckTimers();
}
}, 200);
}
on your add item change this variable value
export function onAddItem(item) {
axios.post('http://localhost:3001/api/items/', item)
.then(res => {
timerFinished = true;
dispatch({
type: "ADD_ITEM",
item
});
dispatch({
type: "ITEM_LOADED",
status: true
});
})
}
and here is how we need to call it.
PostData = (items) => {
timerFinished = false;
onAddItem(items);
this.CheckTimers();
}
If you check this what we done is continuously checking the variable change and emptied only once its done.
One thing you need to handle is to when axios failed to post the data you need to change the variable value to something and handle it, you can do it using the different values 'error','failed','success' to the timerFinished variable.

React Native - data duplicates on firebase data update

I'm using React Native and firebase for the application, where I'm using 'on' for listening to database changes, but whenever data is updated, my data doubles (getting duplicates of every object). I tried resetting the data before forEach loop but it returns the empty data on the last iteration. I was using array earlier and then I tried using Set but still the same result. Any help will be appreciated. Thanks
Here is my code:
friendPost = () => {
let that = this;
let res = new Set();
firebase.database().ref("/Manifest User/"+this.state.currentUsername.charAt(0).toUpperCase()+ "/"+
this.state.currentUsername+"/Friends").on("value", function (snapshot) {
// let result=[];
snapshot.forEach(function (childSnapshot) {
if(childSnapshot.key !== 'Friend Requests'){
res=[];
firebase.database().ref("/Manifest User/"+childSnapshot.key.charAt(0).toUpperCase()+"/"+childSnapshot.key
+"/Profile Posts/").on("value", function (postSnapshot) {
postSnapshot.forEach(function(miniSnapshot){
if(miniSnapshot.key !== '~default') {
let url;
let urlTemp = miniSnapshot.val().post.match(/(http|https|ftp|ftps)\:\/\/[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,3}(\/\S*)?/);
if (urlTemp !== null){
url = urlTemp[0];
if (urlTemp[0].includes("youtu")) {
url = "https://www.youtube.com/embed/"+urlTemp[0].substr(urlTemp[0].lastIndexOf("/")+1);
}
else if (urlTemp[0].includes("vimeo.com")){
url = "https://player.vimeo.com/video/"+urlTemp[0].substr(urlTemp[0].lastIndexOf("/")+1);
}
}
let postString = miniSnapshot.val().post
.replace(/(http|https|ftp|ftps)\:\/\/[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,3}(\/\S*)?/, '');
res.push({
postDate: miniSnapshot.key,
postImage: miniSnapshot.hasChild('postImage') ? miniSnapshot.val().postImage : '',
post: postString,
username: miniSnapshot.hasChild('postUserName') ? miniSnapshot.val().postUserName : '',
comments: miniSnapshot.hasChild('postComments') ? miniSnapshot.val().postComments : [],
likes: miniSnapshot.hasChild('postLikes') ? miniSnapshot.val().postLikes : [],
url: url,
actualPostString: miniSnapshot.hasChild('post') ? miniSnapshot.val().post : '',
});
}
});
// alert(JSON.stringify(res))
that.setState({friendPosts: Array.from(res)});
}.bind(this));
}
});
})
};
A reason for this to be happening is your component re-rendering. The code where you are calling this function is called twice i.e. on a re-render.

JQuery Return the Object with the Promise

I've got multiple pages of widgets. The contents of the widgets are static, though their display can change. I need to be able to store these, so I'm building an multi-dimensional object.
I need to store the object and display the object.
Here's a simplified version of my factory:
const createWidget = ({
id = undefined,
name = 'new widget',
style = 'vertical_list',
html = undefined,
} = {}) => ({
id,
name,
style,
data,
constructWidget () {
return $.ajax({
url: '/my/url',
type: 'POST',
data: {
'_token' : window.xsrf_token,
'widget_id': this.id,
},
dataType: 'json',
}).then(reponse => {
let widget = response.widget;
this.name = widget.name;
this.style = widget.style;
this.html = widget.html;
});
},
})
That hydrates the object with everything just fine, but I can't get the object back.
let book = {};
let page = 'example page';
book[page] = book[page] || {};
let widget_id = 88;
// TRYING TO STORE
// this just give me the promise and I can't get at the object :(
book[page][widget_id] = CreateWidget({id: widget_id}).constructWidget();
// TRYING TO DISPLAY
let widget = book[page][widget_id];
$(`#current_page`).append(`
<div id="widget_${widget.id}" class="${style}">
<b>${widget.name}</b>
${widget.html}
</div>`
);
So? Why is this approach stupid and how do I fix it? I've tried messing with promises a bunch, but without access to the hydrated object I can't seem to do a dang thing.
you need to wait for these promises somehow
simplest (well, the shorter code example at least) way is to use async/await
async function() {
book[page][widget_id] = await CreateWidget_1({id: widget_id}) //the promise :(
book[page][widget_id] = await CreateWidget_2({id: widget_id}) //maybe...
$(`#current_page`).append(`<div>${book[page][widget_id]}</div>`); //nope, that'll be undefined because the promise isn't complete this isn't an asynch approach, dummy
or the longer promises based
Promise.all[CreateWidget_1(...), CreateWidget_2(...)])
.then(function() { $(`#current_page`).append(...) })
Also, chaining is one of the most important concepts of promises, to properly use promise, they need to be returned, both your functions need to return the promise (only one returns it)
The issue was that I needed to return this as part of the promise. I wasn't doing that. Huge thanks to #JaromandaX for that.
Returning the promise and the object means that I continue on a asynchronous path. Simplified example answer below.
const createWidget = ({
id = undefined,
name = 'new widget',
style = 'vertical_list',
html = undefined,
} = {}) => ({
id,
name,
style,
data,
constructWidget () {
return $.ajax({
url : '/my/url',
type: 'POST',
data: {
'_token' : window.xsrf_token,
'widget_id': this.id,
},
dataType: 'json',
}).then(reponse => {
let widget = response.widget;
this.name = widget.name;
this.style = widget.style;
this.html = widget.html;
return this; // <-- here's what I was missing.
});
},
})
let book = {};
let page = 'example page';
book[page] = book[page] || {};
let widget_id = 88;
CreateWidget({id: widget_id})
.constructWidget()
.then(widget => {
book[page][widget_id] = widget;
$(`#current_page`).append(`
<div id="widget_${widget.id}" class="${style}">
<b>${widget.name}</b>
${widget.html}
</div>`
);
})
.fail(error => console.error);
A pox upon the article that said a return inside the then was meaningless!

Call nested methods on object only if it exists using Ramda

I currently have a user object, which has a currentRoom() method on it, which might sometimes not exist or return null.
If the currentRoom() method returns something, I then need to call a messages() method on that. If nothing is returned from either, I’d like to return a default empty array [].
I’d like to tackle this functionally using Ramda, so it’s neat and reusable. Currently, my (non Ramda) code looks like this:
const user = Users.findOne({ username: params.id })
const room = (user.currentRoom && user.currentRoom() || {})
const messages = (room.messages && room.messages() || [])
Some kind of logic I was thinking was to pass in the list of required methods, along with the default result if nothing comes out of it.
/* getMessages(defaultIfNull, methodsArray, object) */
getMessages([], ['currentRoom', 'messages'], user)
Basically something a bit similar to pathOr, but for methods on objects.
I guess I'd use the List monad like an Option:
const getRoom = user => "currentRoom" in user ? [user.currentRoom()] : [];
const getMessages = room => "messages" in room ? room.messages() : [];
const allTogether = R.compose(R.chain(getMessage), R.chain(getRoom), R.of);
console.log(allTogether(Users.findOne({ username: params.id })));
You can use a point-free solution using just Ramda. First, we define a withDefaults function which will set up currentRoom and messages methods in objects which these methods are undefined.
var withDefaults = R.pipe(
// if don't have `currentRom` add a
// `currentRom` function that returns an empty object
R.unless(
R.hasIn('currentRoom'),
R.assoc('currentRoom',
R.always({}))),
// if don't have `messages` add a
// `messages` function that returns an empty array
R.unless(
R.hasIn('messages'),
R.assoc('messages',
R.always([]))))
This function filters the object setting up methods if needed. Usage example.
var user = withDefaults(getById(id))
Next, define a getter functions to get rooms and messages from objects. invoker is the central piece of this snipet, it returns a function that invokes a method. See http://ramdajs.com/docs/#invoker
var getCurrentRoom = R.invoker(0, 'currentRoom')
var getMessages = R.invoker(0, 'messages')
Above code can be used as following.
var userWithRoom = withDefaults({
currentRoom : function () {
return {
number : '123'
}
}
})
var userWithMessages = withDefaults({
messages : function () {
return [
'get lunch'
]
}
})
var userWithAll = withDefaults({
currentRoom : function () {
return {
number : '123'
}
},
messages : function () {
return [
'get lunch'
]
}
})
var userWithNone = withDefaults({})
All together
var withDefaults = R.pipe(
R.unless(
R.hasIn('currentRoom'),
R.assoc('currentRoom',
R.always({}))),
R.unless(
R.hasIn('messages'),
R.assoc('messages',
R.always([]))))
var getCurrentRoom = R.invoker(0, 'currentRoom')
var getMessages = R.invoker(0, 'messages')
// examples
var userWithRoom = withDefaults({
currentRoom : function () {
return {
number : '123'
}
}
})
var userWithMessages = withDefaults({
messages : function () {
return [
'get lunch'
]
}
})
var userWithAll = withDefaults({
currentRoom : function () {
return {
number : '123'
}
},
messages : function () {
return [
'get lunch'
]
}
})
Now lets test above code using console.log to see if our solution works as expected
console.log(getCurrentRoom(userWithRoom))
console.log(getCurrentRoom(userWithMessages))
console.log(getCurrentRoom(userWithAll))
console.log(getCurrentRoom(userWithNone))
console.log('---')
console.log(getMessages(userWithRoom))
console.log(getMessages(userWithMessages))
console.log(getMessages(userWithAll))
console.log(getMessages(userWithNone))
The output should be:
{ number: '123' }
{}
{ number: '123' }
{}
---
[]
[ 'get lunch' ]
[ 'get lunch' ]
[]

Categories

Resources