Data does not update in view - javascript

I am creating an update function in my ionic 4 frontend which has a form to update user info. When I try to change the name, for example, it is updated in the database but is not displayed in the view through interpolation unless I logout and log back in. Here is my update method in the frontend.
updateInfo() {
if (!this.updateForm.valid) {
this.invalidUpdate();
} else {
if (!(this.name === "")) {
var nameObj = {
name: this.name
};
this._userService.updateName(nameObj).subscribe(
data => {
console.log(data);
this.getUserNamePoints();
},
error => {
this.updateFail();
}
);
}
};
this.getUserNamePoints();
}
}
And here is the method updateName(name) in the service
updateName(name) {
var headers = new Headers();
headers.append(
"Authorization",
"Bearer " + this._authService.getAuthorizationToken()
);
headers.append("Content-Type", "application/json");
return this.http
.post(environment.apiUrl + "/user/updateName", name, {
headers
})
.map(res => res.json());
}
This is the method getUserNamePoints() which is also called in the constructor:
getUserNamePoints() {
this._authService.getPoints().subscribe((res: any) => {
this.current = res.data;
this.clientName = res.name;
});
}
And here is the interpolation I am performing:
<h2>
<ion-text color="secondary" style="font-weight:bold">
Hello, {{ clientName }}!</ion-text
>
</h2>
This is my backend method:
module.exports.updateName = function(req, res, next) {
User.findByIdAndUpdate(
req.decodedToken.user._id,
{
$set: req.body
},
{ new: true }
).exec(function(err, updatedUser) {
if (err) {
return next(err);
}
res.status(200).json({
err: null,
msg: "Name was updated successfully.",
data: req.decodedToken.user.name
});
});
};

I think the problem is in your backend. I can see that you are sending the data from the decoded token and the token is encoded when you login, so it does not have the updated data.
res.status(200).json({
err: null,
msg: "Name was updated successfully.",
data: req.decodedToken.user.name
});
Can you show me how are you retrieving the data of the user from your backend when you call the method "getUserNamePoints();" ? Are you looking for the user data in your database or in the decoded token?

Related

How to code a checkbox that saves changes after refreshing page

I'm trying to change the checkbox data on the server using the patch method, but I can't do it. Give me an advise, please, how to do it correctly.
I send a patch request, 202 code is returned. In the preview (developer tools in the browser) it is shown that the changed data is returned from the server, but for some reason the changes do not occur in the db.json file. After I check the checkbox and refresh the page it’s like I never checked the box.
I need an input checkbox that will send a PATCH request to the server to change the TODO-list state.
What I have so far:
async function editCheckbox(id) {
try {
checkbox = {
completed: document.querySelector(`[data-id="${id}"]` + ' input[type="checkbox"]').checked
}
await fetch('http://localhost:8080/todo/' + id, {
method: 'PATCH',
body: JSON.stringify(checkbox),
headers: {
'Content-Type': 'application/json; charset=utf-8',
},
});
} catch (err) {
console.log(err);
}
}
And I use a patch on the route:
app.patch("/todo/:id", (req, res) => {
const { id } = req.params;
let rawdata = fs.readFileSync("db.json", "utf8");
let content = JSON.parse(rawdata);
if (!content.find((i) => i.id == id)) {
return res.status(404).json({ message: "Todo with that id not found" });
} else {
const newTodo = req.body;
const toWrite = content.map((i) => {
if (i.id === id) {
return newTodo;
}
return i;
});
fs.writeFileSync("db.json", JSON.stringify(toWrite), (err) => {
if (err) {
console.error(err);
}
});
res.status(202).json(newTodo);
}
});

How to fix "Error: Can't set headers after they are sent" in Express

I have recently been developing a MERN application and I have recently came into the trouble that express is saying that I am setting headers after they are sent.
I am using mongo db and trying to update a user profile.
I have tried to comment out my res.send points to find the issue but I have failed to do so.
Here is my post method for updating the user profile:
app.post("/api/account/update", (req, res) => {
const { body } = req;
// Validating and Checking Email
if (body.email) {
var email = body.email;
email = email.toLowerCase();
email = email.trim();
body.email = email;
User.find(
{
email: body.email
},
(err, previousUsers) => {
if (previousUsers.length > 0) {
return res.send({
success: false,
message:
"Error: There is already another account with that email address"
});
} else {
}
}
);
}
// Validating Names Function
function checkName(name) {
var alphaExp = /^[a-zA-Z]+$/;
if (!name.match(alphaExp)) {
return res.send({
success: false,
message: "Error: Names cannot contain special characters or numbers"
});
}
}
checkName(body.firstName);
checkName(body.lastName);
// Making sure that all fields cannot be empty
if (!body.email && !body.firstName && !body.lastName) {
return res.send({
success: false,
message: "Error: You cannot submit nothing"
});
}
// Getting User ID from the current session
UserSession.findById(body.tokenID, function(err, userData) {
// Finding User ID using the current users session token
if (userData.isDeleted) {
return res.send({
success: false,
message:
"Error: Session token is no longer valid, please login to recieve a new one"
});
}
// Deleting the token ID from the body object as user table entry doesnt store tokens
delete body.tokenID;
// Finding the user profile and updating fields that are present
User.findByIdAndUpdate(userData.userId, body, function(err, userInfo) {
if (!err) {
return res.send({
success: true,
message: "Success: User was updated successfully"
});
}
});
});
});
This is the call that I am doing to the backend of the site:
onUpdateProfile: function(fieldsObj) {
return new Promise(function(resolve, reject) {
// Get Session Token
const obj = getFromStorage("the_main_app");
// Defining what fields are getting updated
fieldsObj.tokenID = obj.token;
// Post request to backend
fetch("/api/account/update", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(fieldsObj)
})
.then(res => {
console.log("Verify Token - Res");
return res.json();
})
.then(json => {
console.log("Verify Token JSON", json);
if (json.success) {
window.location.href = `/manage-account?success=${json.success}`;
} else {
window.location.href = `/manage-account?success=${json.success}`;
}
});
});
}
Here is my error message that I am getting:
Error: Can't set headers after they are sent.
at validateHeader (_http_outgoing.js:491:11)
at ServerResponse.setHeader (_http_outgoing.js:498:3)
at ServerResponse.header (C:\Users\kieran.corkin\Desktop\Projects\Mern Template Final\mern-cra-and-server\server\node_modules\express\lib\response.js:767:10)
at ServerResponse.send (C:\Users\kieran.corkin\Desktop\Projects\Mern Template Final\mern-cra-and-server\server\node_modules\express\lib\response.js:170:12)
at ServerResponse.json (C:\Users\kieran.corkin\Desktop\Projects\Mern Template Final\mern-cra-and-server\server\node_modules\express\lib\response.js:267:15)
at ServerResponse.send (C:\Users\kieran.corkin\Desktop\Projects\Mern Template Final\mern-cra-and-server\server\node_modules\express\lib\response.js:158:21)
at C:\Users\kieran.corkin\Desktop\Projects\Mern Template Final\mern-cra-and-server\server\routes\api\account.js:270:22
at C:\Users\kieran.corkin\Desktop\Projects\Mern Template Final\mern-cra-and-server\server\node_modules\mongoose\lib\model.js:4641:16
at process.nextTick (C:\Users\kieran.corkin\Desktop\Projects\Mern Template Final\mern-cra-and-server\server\node_modules\mongoose\lib\query.js:2624:28)
at _combinedTickCallback (internal/process/next_tick.js:131:7)
at process._tickCallback (internal/process/next_tick.js:180:9)
[nodemon] app crashed - waiting for file changes before starting...
Can anyone help me with this?
EDIT
I have changed my code, this seems to now work however I feel like its a little messy when put together. Any refactoring tips?
Code:
app.post("/api/account/update", (req, res) => {
// Preform checks on data that is passed through
const { body } = req;
var messages = {
ExistedUser:
"Error: There is already another account with that email address",
NameFormat: "Error: Names cannot contain special characters or numbers",
BlankInputs: "Error: You cannot submit nothing",
accountLoggedOut:
"Error: Session token is no longer valid, please login to recieve a new one",
successfullyUpdated: "Success: User was updated successfully"
};
var usersFound;
if (body.email) {
var email = body.email;
email = email.toLowerCase();
email = email.trim();
body.email = email;
User.find(
{
email: body.email
},
(err, UserCount) => {
usersFound = UserCount;
}
);
}
function capitalize(text) {
return text.replace(/\b\w/g, function(m) {
return m.toUpperCase();
});
}
if (body.firstName) {
body.firstName = capitalize(body.firstName);
}
if (body.lastName) {
body.lastName = capitalize(body.lastName);
}
//Making sure that all fields cannot be empty
if (!body.email && !body.firstName && !body.lastName) {
return res.send({
success: false,
message: messages.BlankInputs
});
}
// Getting User ID from the current session
UserSession.findById(body.tokenID, function(err, userData) {
// Finding User ID using the current users session token
if (userData.isDeleted) {
return res.end({
success: false,
message: messages.accountLoggedOut
});
}
if (userData) {
// Deleting the token ID from the body object as user table entry doesnt store tokens
delete body.tokenID;
// Finding the user profile and updating fields that are present
User.findByIdAndUpdate(userData.userId, body, function(err, userInfo) {
if (userInfo) {
if (!usersFound.length > 0) {
return res.send({
success: true,
message: messages.successfullyUpdated
});
} else {
return res.send({
success: false,
message: messages.ExistedUser
});
}
}
});
}
});
});
You're calling res.send() twice. res.send() ends the process. You ought to refactor such that you call res.write() and only call res.send() when you're done.
This StackOverflow link describes the difference in more detail. What is the difference between res.send and res.write in express?
I believe this is happening, as you're trying to send a response after the first / initial response has already been sent to the browser. For example:
checkName(body.firstName);
checkName(body.lastName);
Running this function twice is going to try and yield 2 different "response" messages.
The product of a single route, should ultimately be a single response.
Thanks for all your help on this issue.
Here is my final code that allowed it to work.
I have also tried to "refactor" it too. Let me know if you'd do something else.
app.post("/api/account/update", (req, res) => {
const { body } = req;
console.log(body, "Logged body");
// Defining objects to be used at the end of request
var updateUserInfo = {
userInfo: {},
sessionToken: body.tokenID
};
var hasErrors = {
errors: {}
};
// Checking that there is at least one value to update
if (!body.email && !body.firstName && !body.lastName) {
var blankError = {
success: false,
message: "Error: You cannot change your details to nothing"
};
hasErrors.errors = { ...hasErrors.errors, ...blankError };
} else {
console.log("Normal Body", body);
clean(body);
console.log("Cleaned Body", body);
updateUserInfo.userInfo = body;
delete updateUserInfo.userInfo.tokenID;
}
// Function to check if object is empty
function isEmpty(obj) {
if (Object.keys(obj).length === 0) {
return true;
} else {
return false;
}
}
// Function to remove objects from body if blank
function clean(obj) {
for (var propName in obj) {
if (obj[propName] === "" || obj[propName] === null) {
delete obj[propName];
}
}
}
// Checking and Formatting Names Given
function capitalize(text) {
return text.replace(/\b\w/g, function(m) {
return m.toUpperCase();
});
}
if (body.firstName) {
body.firstName = capitalize(body.firstName);
}
if (body.lastName) {
body.lastName = capitalize(body.lastName);
}
// Checking and formatting email
if (body.email) {
body.email = body.email.toLowerCase();
body.email = body.email.trim();
// Checking for email in database
User.find({ email: body.email }, (err, EmailsFound) => {
if (EmailsFound.length > 0) {
var EmailsFoundErr = {
success: false,
message: "There is already an account with that email address"
};
hasErrors.errors = { ...hasErrors.errors, ...EmailsFoundErr };
}
});
}
// Getting User Session Token
UserSession.findById(updateUserInfo.sessionToken, function(err, userData) {
// Finding User ID using the current users session token
if (userData.isDeleted) {
var userDeletedError = {
success: false,
message:
"Your account is currently logged out, you must login to change account details"
};
hasErrors.errors = { ...hasErrors.errors, ...userDeletedError };
} else {
// Finding the user profile and updating fields that are present
User.findByIdAndUpdate(
userData.userId,
updateUserInfo.userInfo,
function(err, userInfo) {
// userInfo varable contains user db entry
if (err) {
var updateUserError = {
success: false,
message: "Error: Server Error"
};
hasErrors.errors = {
...hasErrors.errors,
...updateUserError
};
}
if (isEmpty(hasErrors.errors)) {
res.send({
success: true,
message: "Success: You have updated your profile!"
});
} else {
res.send({
success: false,
message: hasErrors.errors
});
}
}
);
}
});
});

How to get user.id from jwt token in Node.js?

In my User controller, I create a token in which I save this user's id when he login to my application.
exports.findOne = (req, res) => {
User.findOne({
where: {
login: req.body.login,
},
})
.then(user => {
if (user) {
if (bcrypt.compareSync(req.body.password, user.password)) {
const token = jwt.sign(
{
id: user.id, // this is the id I need.
},
env.SECRET_KEY,
{
expiresIn: 129600,
},
);
return res.status(200).json({
message: 'Auth successful',
token,
});
}
...
}
})
.catch(err => {
res.status(400).json({ error: err });
});
};
Now in another controller I would like to read this id and use it for my purpose. How can I get to it?
const loginId = '?'; // here I want to give it to id
Bill.update(
{
available_funds: available_funds - amountMoney,
},
{ where: { id_owner: loginId } },
).then(() => {
res.status(200).send(`ok`);
});
Make a middleware which checks the incoming token before forwarding to your update route.
This middleware should be responsible for validating the incoming token which you pass from the client side code after logging in (storing token in cookies is commonly practiced).
Now in your middleware, you can do something similar to this:
app.use(function(req,res,next) {
JWT.verify(req.cookies['token'], 'YOUR_SECRET', function(err, decodedToken) {
if(err) { /* handle token err */ }
else {
req.userId = decodedToken.id; // Add to req object
next();
}
});
});
Then, finally in your upcoming controller, you can access the id from the request object:
const loginId = req.userId;
Bill.update(
{
available_funds: available_funds - amountMoney,
},
{ where: { id_owner: loginId } },
).then(() => {
res.status(200).send(`ok`);
});
You don't need to add extra codes. To access the userId use this:
req.payload.id

Dynamically adding post at the site using Observables (Angular)

I need to display posts dynamically on my home page. I have textarea above the post lists and my goal is to display new post immediatelly after it would be added, on the top of the post list. Component with textarea form is called add-post-component and it use onSubmit event:
onAddPostSubmit() {
if (this.authService.loggedIn()) {
const post = {
content: this.content,
creator_username: JSON.parse(localStorage.getItem('user')).username,
rate: 0
};
this.postsService.addPost(post).subscribe(data => {
if (data.success) {
console.log('Post added');
this.router.navigate(['/']);
} else {
console.log('Post not added' + JSON.stringify(data));
this.router.navigate(['/']);
}
});
} else {
console.log('Not logged');
return false;
}
}
Component of my main page is called Feed-component
this.postsService.getPosts().subscribe(response => {
this.posts = response.posts.reverse();
}),
err => {
console.log(err);
return false;
};
this.subscription = this.postsService.fetchPost().subscribe(post => {
this.postsService.getPosts().subscribe(response => {
this.posts = response.posts.reverse();
}),
err => {
console.log(err);
return false;
};
});
Both components use posts service:
getPosts() {
let headers = new Headers();
headers.append('Content-Type', 'application/json');
return this.http.get('http://localhost:3000/posts/fetch', {headers: headers})
.map(res => res.json());
}
addPost(post) {
let headers = new Headers();
headers.append('Content-Type', 'application/json');
this.subject.next({post});
return this.http.post('http://localhost:3000/posts/add', post, {headers: headers})
.map(res => res.json());
}
fetchPost(): Observable<any> {
return this.subject.asObservable();
}
As you can see, I use Observable methodology to process data between components. The problem which I have is that post list is updating after I add post to database, but without the last added post. So if I would add two posts - 1) 'abc' and 2) 'cba', after send 'abc' anything happened, and when I add 'cba' list will be updated with 'abc' on the top.
I think the case is that addPost method is calling after getPosts and fetchPost.
How to fix that?

Node Js findByIdAndUpdate function not updating in db

Im updating products based on its id in nodejs by creating API and calling them in angular 2 services.
routes/products.js
router.post('/:id', function(req, res, next) {
Products.findByIdAndUpdate(req.params.id, req.body, function (err, post) {
if(err){
res.json({success: false, msg:'Failed updating products'});
} else {
res.json({success: true, msg:'success updating products'});
}
});
});
This is how im passing in postman: POST request
{
"id":"596df0ffcb429a586ef6c0bf",
"category_id": "596ddb165314d15618795826",
"product_name":"Laysssss masala",
"product_price":5,
"product_image":"image1ddd",
"product_desc":"Yummyddsd",
"product_status":"Activedddd"
}
Products seem to be saved in DB.
The same when i call in services under angular and try in browser, i get "Product updated successfully" in broswer , but not reflecting in DB.
component.ts
onSaveConfirm(event) {
if (window.confirm('Are you sure you want to save?')) {
// var prodId = event.newData['_id']
//console.log(event.newData)
this.productService.productUpdate(event.newData).subscribe(data => {
if (data.success) {
console.log('Edited success')
this.flashMessage.show('Product updated successfully', { cssClass: 'alert-success', timeout: 3000 });
this.router.navigate(['/category-items']);
} else {
console.log('failure edited...')
this.flashMessage.show('Something went wrong', { cssClass: 'alert-danger', timeout: 3000 });
this.router.navigate(['/category-items']);
}
});
event.confirm.resolve(event.newData);
} else {
event.confirm.reject();
}
}
product.service.ts
productUpdate(products) {
var prodId = products['_id'];
console.log(products)
let prodUrl = "http://localhost:8080/products/" + prodId
let headers = new Headers();
headers.append('Content-Type', 'application/json');
let prodIdObj = JSON.stringify({ products: products })
return this.http.post(prodUrl, prodIdObj, { headers: headers })
.map((response: Response) => response.json())
.do(data => JSON.stringify(data))
.catch(this.handleError);
}
Maybe your problem here:
In product.service.ts:
productUpdate(products) {
//skipped
let prodUrl = "http://localhost:8080/products/" + prodId
//skipped
}
and products.js
router.post('/:id', function(req, res, next) {
Products.findByIdAndUpdate(req.params.id, req.body, function (err, post) {
if(err){
res.json({success: false, msg:'Failed updating products'});
} else {
res.json({success: true, msg:'success updating products'});
}
});
});
change it to:
router.post('products/:id', function(req, res, next) {
//do something
});

Categories

Resources