How to efficiently show a users change/update - node.js

I have a moments component which is similar to a thread/post. Users can like or dislike this moment. Once they like the moment i call the momentService to retrieve the entire list again so it refreshes and increases the like count of the moment.
However, as im only liking one post its not efficient to update all the other moments. Whats the best way to show this update/change without having to get all the moments again.
When i call the update i retrieve the updated moment object. So is there a way to update this specific moment in the moments object.
moments.component.html
<mat-card class="" *ngFor="let moment of moments">
<mat-card-header class="sub-header" fxLayout="row" fxLayoutAlign="space-between center">
<mat-card-subtitle>
{{moment.created_at}}
</mat-card-subtitle>
<mat-card-title>
<img src="http://via.placeholder.com/50x50" alt="" class="img-circle">
</mat-card-title>
<div>
<button mat-icon-button color="warn" matTooltip="Delete" (click)="delete(moment._id)">
<mat-icon>delete</mat-icon>
</button>
<button mat-icon-button>
<mat-icon>more_vert</mat-icon>
</button>
</div>
</mat-card-header>
<mat-card-content>
<p>
{{moment.body}}
</p>
</mat-card-content>
<mat-card-actions fxLayout="row" fxLayoutAlign="space-between center">
<div>
<button mat-icon-button matTooltip="Like" (click)="like(moment._id)">
<mat-icon>thumb_up</mat-icon> {{moment.likes.length}}
</button>
<button mat-icon-button matTooltip="Dislike" (click)="dislike(moment._id)">
<mat-icon>thumb_down</mat-icon> {{moment.dislikes.length}}
</button>
</div>
<button mat-icon-button matTooltip="Comments">
<mat-icon>comment</mat-icon> {{moment.comments.length}}
</button>
</mat-card-actions>
</mat-card>
moment.component.ts
import { Component, OnInit } from '#angular/core';
import { AuthService } from '../../../services/auth.service';
import { MomentService } from '../../../services/moment.service';
import { Router, ActivatedRoute, ParamMap } from '#angular/router';
import { UserService } from '../../../services/user.service';
#Component({
selector: 'app-moments',
templateUrl: './moments.component.html',
styleUrls: ['./moments.component.scss']
})
export class MomentsComponent implements OnInit {
user: any;
moments: any;
constructor(private authService: AuthService,
private userService: UserService,
private momentService: MomentService,
private route: ActivatedRoute,
private router: Router) { }
ngOnInit() {
this.route.parent.paramMap.switchMap((params: ParamMap) => {
let user_id = params.get('id');
return this.userService.get(user_id);
}).subscribe((res) => {
this.user = res;
console.log(this.user._id);
this.getMoments();
});
}
getMoments() {
this.momentService.all(this.user._id).subscribe((res) => {
this.moments = res.data;
}, (err) => {
console.log(err);
});
}
like(moment) {
let like = { 'like': this.user._id };
this.momentService.update(moment, like).subscribe((res) => {
this.getMoments();
console.log(res);
}, (err) => {
console.log(err);
});
}
dislike(moment) {
let dislike = { 'dislike': this.user._id };
this.momentService.update(moment, dislike).subscribe((res) => {
this.getMoments();
console.log(res);
}, (err) => {
console.log(err);
});
}
delete(moment) {
let id = moment;
this.momentService.delete(id).subscribe((res) => {
this.getMoments();
console.log(res);
}, (err) => {
console.log(err);
})
}
}
moments.service.ts
import { HttpParams } from '#angular/common/http';
import { Injectable } from '#angular/core';
import { ApiService } from './api.service';
#Injectable()
export class MomentService {
path = 'moment/';
constructor(private apiService: ApiService) { }
create(user_id, moment) {
let endpoint = this.path;
return this.apiService.post(endpoint, moment);
}
delete(moment_id) {
let endpoint = this.path + moment_id;
return this.apiService.delete(endpoint);
}
all(user_id) {
let endpoint = this.path;
let params = new HttpParams().set('author', user_id);
return this.apiService.get(endpoint, params);
}
get(moment_id) {
let endpoint = this.path + moment_id;
return this.apiService.get('endpoint');
}
update(moment_id, data) {
let endpoint = this.path + moment_id;
return this.apiService.put(endpoint, data);
}
search(filters) {
let endpoint = this.path;
let params = new HttpParams().set('filters', filters);
return this.apiService.get(endpoint, params);
}
}
moment.controller.js (backend api)
update(req, res) {
let id = req.params.id;
Moment.findOne({ '_id': id }, (err, moment) => {
if (req.body.body) {
moment.body = req.body.body;
}
// LIKE&DISLIKE Toggle
if (req.body.like) {
if (moment.dislikes.indexOf(req.body.like) > -1) {
moment.dislikes.remove(req.body.like);
}
if (moment.likes.indexOf(req.body.like) > -1) {
moment.likes.remove(req.body.like);
} else {
moment.likes.push(req.body.like);
}
}
if (req.body.dislike) {
if (moment.likes.indexOf(req.body.dislike) > -1) {
moment.likes.remove(req.body.dislike);
}
if (moment.dislikes.indexOf(req.body.dislike) > -1) {
moment.dislikes.remove(req.body.dislike);
} else {
moment.dislikes.push(req.body.dislike);
}
}
moment.save((err, moment) => {
if (err) {
return res.status(404).json({
success: false,
status: 404,
data: {},
mesage: "Failed to update moment"
});
}
return res.status(201).json({
succss: true,
status: 201,
data: moment,
message: "Succesfully updated moment",
});
});
})
}

Instead of passing the id to the like/dislike methods, you can pass the entire object and from there pass the id to the update method, and on success, mutate the reference.

Related

How to update the user feed after updating the post?

I have a UserFeed component and EditForm component. As soon as I edit the form, I need to be redirected to the UserFeed and the updated data should be shown on UserFeed(title and description of the post).
So, the flow is like-UserFeed, which list the posts, when click on edit,redirected to EditForm, updates the field, redirected to UserFeed again, but now UserFeed should list the posts with the updated data, not the old one.
In this I'm just redirectin to / just to see if it works. But I need to be redirected to the feed with the updated data.
EditForm
import React, { Component } from "react";
import { connect } from "react-redux";
import { getPost } from "../actions/userActions"
class EditForm extends Component {
constructor() {
super();
this.state = {
title: '',
description: ''
};
handleChange = event => {
const { name, value } = event.target;
this.setState({
[name]: value
})
};
componentDidMount() {
const id = this.props.match.params.id
this.props.dispatch(getPost(id))
}
componentDidUpdate(prevProps) {
if (prevProps.post !== this.props.post) {
this.setState({
title: this.props.post.post.title,
description: this.props.post.post.description
})
}
}
handleSubmit = () => {
const id = this.props.match.params.id
const data = this.state
this.props.dispatch(updatePost(id, data, () => {
this.props.history.push("/")
}))
}
render() {
const { title, description } = this.state
return (
<div>
<input
onChange={this.handleChange}
name="title"
value={title}
className="input"
placeholder="Title"
/>
<textarea
onChange={this.handleChange}
name="description"
value={description}
className="textarea"
></textarea>
<button>Submit</button>
</div>
);
}
}
const mapStateToProps = store => {
return store;
};
export default connect(mapStateToProps)(EditForm)
UserFeed
import React, { Component } from "react"
import { getUserPosts, getCurrentUser } from "../actions/userActions"
import { connect } from "react-redux"
import Cards from "./Cards"
class UserFeed extends Component {
componentDidMount() {
const authToken = localStorage.getItem("authToken")
if (authToken) {
this.props.dispatch(getCurrentUser(authToken))
if (this.props && this.props.userId) {
this.props.dispatch(getUserPosts(this.props.userId))
} else {
return null
}
}
}
render() {
const { isFetchingUserPosts, userPosts } = this.props
return isFetchingUserPosts ? (
<p>Fetching....</p>
) : (
<div>
{userPosts &&
userPosts.map(post => {
return <Cards key={post._id} post={post} />
})}
</div>
)
}
}
const mapStateToPros = state => {
return {
isFetchingUserPosts: state.userPosts.isFetchingUserPosts,
userPosts: state.userPosts.userPosts.userPosts,
userId: state.auth.user._id
}
}
export default connect(mapStateToPros)(UserFeed)
Cards
import React, { Component } from "react"
import { connect } from "react-redux"
import { compose } from "redux"
import { withRouter } from "react-router-dom"
class Cards extends Component {
handleEdit = _id => {
this.props.history.push(`/post/edit/${_id}`)
}
render() {
const { _id, title, description } = this.props.post
return (
<div className="card">
<div className="card-content">
<div className="media">
<div className="media-left">
<figure className="image is-48x48">
<img
src="https://bulma.io/images/placeholders/96x96.png"
alt="Placeholder image"
/>
</figure>
</div>
<div className="media-content" style={{ border: "1px grey" }}>
<p className="title is-5">{title}</p>
<p className="content">{description}</p>
<button
onClick={() => {
this.handleEdit(_id)
}}
className="button is-success"
>
Edit
</button>
</div>
</div>
</div>
</div>
)
}
}
const mapStateToProps = state => {
return {
nothing: "nothing"
}
}
export default compose(withRouter, connect(mapStateToProps))(Cards)
updatePost action
export const updatePost = (id, data, redirect) => {
return async dispatch => {
dispatch( { type: "UPDATING_POST_START" })
try {
const res = await axios.put(`http://localhost:3000/api/v1/posts/${id}/edit`, data)
dispatch({
type: "UPDATING_POST_SUCCESS",
data: res.data
})
redirect()
} catch(error) {
dispatch({
type: "UPDATING_POST_FAILURE",
data: { error: "Something went wrong"}
})
}
}
}
I'm not sure if my action is correct or not.
Here's the updatePost controller.
updatePost: async (req, res, next) => {
try {
const data = {
title: req.body.title,
description: req.body.description
}
const post = await Post.findByIdAndUpdate(req.params.id, data, { new: true })
if (!post) {
return res.status(404).json({ message: "No post found "})
}
return res.status(200).json({ post })
} catch(error) {
return next(error)
}
}
One mistake is that to set the current fields you need to use $set in mongodb , also you want to build the object , for example if req.body does not have title it will generate an error
updatePost: async (req, res, next) => {
try {
const data = {};
if(title) data.title=req.body.title;
if(description) data.description=req.body.description
const post = await Post.findByIdAndUpdate(req.params.id, {$set:data}, { new: true })
if (!post) {
return res.status(404).json({ message: "No post found "})
}
return res.status(200).json({ post })
} catch(error) {
return next(error)
}
}

Why am I receiving the following error when subscribed to the patientAllergies observable?

When I select the add button in the patient-allergies.component.ts, select options for the addition of patient allergies and click save, I receive the following error:
ERROR Error: Error trying to diff '[object Object]'. Only arrays and iterables are allowed.
I cannot understand why I am receiving this error as I cast the object to an array when it is passed from the rest-api.service.ts through _patientAllergies.next().
patient-allergies.component.html
<mat-card class="mat-typography">
<mat-card-title>Allergies</mat-card-title>
<mat-card-content>
<hr>
<div *ngFor="let patientAllergy of this.patientAllergies">
<h3 *ngIf="!patientAllergy.nickname"> {{ patientAllergy.fullname }} </h3>
<h3 *ngIf="patientAllergy.nickname"> {{ patientAllergy.fullname }} ({{ patientAllergy.nickname }}) </h3>
</div>
</mat-card-content>
<mat-card-actions *ngIf="isEdit">
<button mat-button class="dark" (click)="onAdd()">ADD</button>
<button mat-button class="dark" (click)="onRemove()">REMOVE</button>
</mat-card-actions>
</mat-card>
<mat-card *ngIf="isLoading" style="display: flex; justify-content: center; align-items: center">
<mat-progress-spinner class="mat-spinner-color" mode="indeterminate"></mat-progress-spinner>
</mat-card>
patient-allergies.component.ts
import {Component, OnInit, Input, Pipe, PipeTransform} from '#angular/core';
import {RestAPIService} from 'src/app/rest-api.service';
import {ActivatedRoute} from '#angular/router';
import {MatDialog} from '#angular/material';
#Component({selector: 'app-patient-allergies', templateUrl: './patient-allergies.component.html', styleUrls: ['./patient-allergies.component.css']})
export class PatientAllergiesComponent implements OnInit {
#Input()isEdit : boolean = false;
constructor(private restAPIService : RestAPIService, private route : ActivatedRoute, public dialog : MatDialog) {}
isLoading : boolean;
patientAllergies;
subscription = null;
ngOnInit() {
this.isLoading = true;
this
.restAPIService
.getPatientAllergies(this.route.snapshot.params.id);
this.subscription = this
.restAPIService
.patientAllergies
.subscribe((patAllergies) => {
this.patientAllergies = patAllergies as [];
this.isLoading = false;
});
}
onAdd() {
let dRef = this
.dialog
.open(AllergiesDialogComponent, {
disableClose: true,
height: '800px',
width: '600px',
data: {
isAdding: true,
patientAllergies: this.patientAllergies
}
});
dRef
.afterClosed()
.subscribe((res) => {
res.forEach((ele) => {
this
.restAPIService
.addPatientAllergies(this.route.snapshot.params.id, ele.value.allergyID);
});
});
}
onRemove() {
let dRef = this
.dialog
.open(AllergiesDialogComponent, {
disableClose: true,
height: '800px',
width: '600px',
data: {
isAdding: false,
patientAllergies: this.patientAllergies
}
});
dRef
.afterClosed()
.subscribe((res) => {
res.forEach((ele) => {
this
.restAPIService
.deletePatientAllergies(this.route.snapshot.params.id, ele.value.allergyID);
});
})
}
}
import {Inject} from '#angular/core';
import {MatDialogRef, MAT_DIALOG_DATA} from '#angular/material';
import {DialogData} from 'src/app/patient/patient.component';
#Component({selector: 'app-allergies-dialog', templateUrl: './allergies-dialog.component.html', styleUrls: ['./allergies-dialog.component.css']})
export class AllergiesDialogComponent implements OnInit {
allergies = [];
filterName : string;
subscription;
constructor(public dialogRef : MatDialogRef < AllergiesDialogComponent >, #Inject(MAT_DIALOG_DATA)public data : DialogData, private restAPIService : RestAPIService) {}
ngOnInit() {
this
.restAPIService
.getAllergies();
if (this.data['isAdding']) {
this.subscription = this
.restAPIService
.allergies
.subscribe((allergies) => {
let allergiesArr = allergies as [];
this.allergies = [];
let patientAllergyNames = [];
this
.data['patientAllergies']
.forEach(patientAllergy => {
patientAllergyNames.push(patientAllergy['fullname'])
});
allergiesArr.forEach(allergy => {
if (!patientAllergyNames.includes(allergy['fullname']))
this.allergies.push(allergy);
}
);
})
} else {
this.allergies = this.data['patientAllergies'];
}
}
onClose(selectedOptions) {
if (this.data['isAdding'])
this.subscription.unsubscribe();
// either [] or the IDs of the objects to add/remove
this
.dialogRef
.close(selectedOptions);
}
}
#Pipe({name: 'filterOnName'})
export class filterNames implements PipeTransform {
transform(listOfObjects : any, nameToFilter : string) : any {
let allergyArr = listOfObjects as[];
let matchedObjects = [];
if (!listOfObjects)
return null;
if (!nameToFilter)
return listOfObjects;
allergyArr.forEach(allergyObj => {
let fullname : string = allergyObj['fullname'];
let nickname : string = allergyObj['nickname'];
let fullnameLower = fullname.toLowerCase();
let nicknameLower = fullname.toLowerCase();
let filter = nameToFilter.toLowerCase();
if (nickname) {
if ((fullnameLower.includes(filter) || nicknameLower.includes(filter)))
matchedObjects.push(allergyObj);
}
else {
if (fullnameLower.includes(filter))
matchedObjects.push(allergyObj);
}
});
return matchedObjects;
}
}
rest-api.service.ts
private _allergies;
private allergiesSubject = new Subject();
allergies = this
.allergiesSubject
.asObservable();
private _patientAllergies;
private patientAllergiesSubject = new Subject();
patientAllergies = this
.patientAllergiesSubject
.asObservable();
getPatientAllergies(patientID) {
const request = {
headers: {},
response: true
};
API
.get('DiagnetAPI', '/v1/patients/' + patientID + '/allergies', request)
.then(resp => {
this._patientAllergies = resp.data;
this
.patientAllergiesSubject
.next(this._patientAllergies);
})
.catch((err) => console.log(err))
}
addPatientAllergies(patientID, allergyID) {
const request = {
headers: {},
response: true,
body: allergyID
};
API
.post('DiagnetAPI', '/v1/patients/' + patientID + '/allergies', request)
.then(resp => {
console.log(resp.data);
this._patientAllergies = resp.data;
this
.patientAllergiesSubject
.next(this._patientAllergies);
})
.then(() => {
this.getPatientAllergies(patientID);
})
.catch((err) => console.log(err))
}
deletePatientAllergies(patientID, allergyID) {
const request = {
headers: {},
response: true
};
API
.del('DiagnetAPI', '/v1/patients/' + patientID + '/allergies/' + allergyID, request)
.then((res) => console.log(res))
.then(() => {
this.getPatientAllergies(patientID);
})
.catch((err) => console.log(err))
}
If your response from the api is not an array but an object, you can use the keyvalue pipe in your *ngFor loop.
In your case patientAllergy would be an object with two keys, the key and the value so you can access the nickname like this: patientAllergy.value.nickname
your template:
<div *ngFor="let patientAllergy of this.patientAllergies | keyvalue">
<h3 *ngIf="!patientAllergy.value.nickname"> {{ patientAllergy.value.fullname }} </h3>
<h3 *ngIf="patientAllergy.value.nickname"> {{ patientAllergy.value.fullname }} ({{ patientAllergy.value.nickname }}) </h3>
</div>

Angular get blog by id not displaying anything on browser

I'm building a blog application based on MEAN stack, using Angular in front-end, node in back-end and mongoDB for server. When I'm trying to access a particular blog by it's blogId, the browser is not showing anything. Although I'm getting the right data fetched from backend with a 304 status and the right blogId is also passing by the route. The console is also logging the right object. Below is my blog-view.component.ts file
import { ActivatedRoute, Router } from '#angular/router';
import { ToastrManager } from 'ng6-toastr-notifications';
import { BlogService } from '../blog.service';
import { BlogHttpService } from '../blog-http.service';
import { Location } from '#angular/common';
#Component({
selector: 'app-blog-view',
templateUrl: './blog-view.component.html',
styleUrls: ['./blog-view.component.css'],
providers: [Location]
})
export class BlogViewComponent implements OnInit, OnDestroy {
public currentBlog;
constructor(private _route: ActivatedRoute, private router: Router, public blogHttpService:BlogHttpService, public toastr: ToastrManager, private location: Location) {
console.log("view-blog constructor called")
}
ngOnInit() {
console.log("view-blog ngOnInIt called");
let myBlogId = this._route.snapshot.paramMap.get('blogId');
console.log(myBlogId);
this.currentBlog = this.blogHttpService.getSingleBlogInformation(myBlogId).subscribe(
data =>{
console.log(data);
this.currentBlog = data["data"];
},
error =>{
console.log("some error occured");
console.log(error.errorMessage);
})
}
public deleteThisBlog(): any {
this.blogHttpService.deleteBlog(this.currentBlog.blogId).subscribe(
data =>{
console.log(data);
this.toastr.successToastr('This blog is successfully deleted.', 'Success!');
setTimeout(() =>{
this.router.navigate(['/home']);
}, 1000)
},
error =>{
console.log(error);
console.log(error.errorMessage);
this.toastr.errorToastr('Some Error Occured.', 'Oops!');
}
)
}
public goBackToPreviousPage(): any {
this.location.back();
}
ngOnDestroy(){
console.log("view-blog component destroyed");
}
}
blog-view.component.html
<div class="row" *ngIf="currentBlog" style="text-align: center;">
<div class="col-md-12">
<h2>{{currentBlog.title}}</h2>
<p>posted by {{currentBlog.author}} on {{currentBlog.created | date:'medium'}}</p>
<p *ngIf="currentBlog.tags!=undefined && currentBlog.tags.length>0">tags : <span *ngFor="let tag of currentBlog.tags;let first=first;let last=last">{{tag}}{{last ? '' : ', '}}</span></p>
<hr>
<div [innerHtml]="currentBlog.bodyHtml"></div>
<hr>
<h5>category - {{currentBlog.category}}</h5>
</div>
<hr>
<div class="row" *ngIf="currentBlog">
<div class="col-md-4">
<a class="btn btn-primary" [routerLink]="['/edit',currentBlog.blogId]">Edit</a>
</div>
<div class="col-md-4">
<a class="btn btn-danger" (click)="deleteThisBlog()">Delete</a>
</div>
<div class="col-md-4">
<a class="btn btn-warning" (click)="goBackToPreviousPage()">Go Back</a>
</div>
</div>
</div>
</div>
blog-http.service.ts
import { HttpClient, HttpErrorResponse } from '#angular/common/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/catch';
import 'rxjs/add/operator/do';
#Injectable()
export class BlogHttpService {
public allBlogs;
public currentBlog;
public baseUrl = 'http://localhost:3000/api/v1/blogs';
constructor(private _http:HttpClient) {
console.log('blog http service constructor called');
}
private handleError(err:HttpErrorResponse){
console.log("handle error http calls");
console.log(err.message);
return Observable.throw(err.message)
}
public getAllBlogs(): any {
let myResponse = this._http.get(this.baseUrl + '/all');
console.log(myResponse);
return myResponse;
}
public getSingleBlogInformation(currentBlogId): any {
let myResponse = this._http.get(this.baseUrl + '/view/' + currentBlogId);
return myResponse;
}
public createBlog(blogData): any {
let myResponse = this._http.post(this.baseUrl + '/create', blogData);
return myResponse;
}
public deleteBlog(blogId): any {
let data = {}
let myResponse = this._http.post(this.baseUrl + '/' + blogId + '/delete', blogId);
return myResponse;
}
public editBlog(blogId, blogData): any {
let myResponse = this._http.put(this.baseUrl + '/' + blogId + '/edit' , blogData);
return myResponse;
}
}
my nodejs routes with controller for blog-view
app.get(baseUrl+'/view/:blogId', (req, res) => {
BlogModel.findOne({ 'blogId': req.params.blogId }, (err, result) => {
if (err) {
console.log(err)
res.send(err)
} else if (result == undefined || result == null || result == '') {
console.log('No Blog Found')
res.send("No Blog Found")
} else {
res.send(result)
}
})
});
Below is a sample document object from which the frontend should render
{
"_id": "5e0e8ac6dcfc4e2008390cdf",
"blogId": "XAY2Qlhb",
"__v": 0,
"lastModified": "2020-01-03T00:28:54.638Z",
"created": "2020-01-03T00:28:54.638Z",
"tags": [
"english movies, action movies"
],
"author": "Decardo",
"category": "Hollywood custom",
"isPublished": true,
"views": 8,
"bodyHtml": "<h1>Heading of the body</h1>\n<p>This is the first blog data getting uploaded n blog project</p>",
"description": "long description>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>",
"title": "Blog Title 1 custom"
}
This line of code will first store a Subscription in this.currentBlog:
this.currentBlog = this.blogHttpService.getSingleBlogInformation(myBlogId).subscribe(...)
Then the subscription will be overwritten by this.currentBlog = data["data"];
this.currentBlog = is actually not needed there.
Not sure if that is the problem. At least it is not proper :)

How to get data back in frontend from database after posting

import { Component, OnInit, Input } from '#angular/core';
import { Router } from '#angular/router';
import { FormBuilder, FormGroup, FormArray } from '#angular/forms';
import { Validators } from '#angular/forms';
import { HttpService } from '../http.service';
#Component({
selector: 'todo-app',
templateUrl: './todo-app.component.html',
styleUrls: ['./todo-app.component.css']
})
export class TodoAppComponent implements OnInit {
myForm: FormGroup;
todoitems = [];
todolist;
submitted = false;
name;
constructor(private router: Router, private formBuilder: FormBuilder, private httpService: HttpService ) {
}
ngOnInit() {
this.myForm = this.formBuilder.group({
todoitems : [this.todolist, Validators.compose([Validators.required, Validators.minLength(3)])]
});
this.httpService.gettodo().subscribe(
(data:any[]) => {
this.todoitems = data;
console.log(this.name);
}
);
}
addTodo() {
if (this.myForm.invalid) {
this.submitted = true;
}
if (this.myForm.valid) {
var body = { name: this.todolist }
this.httpService.addTodoo(body).subscribe(
(data:any) => {
this.todoitems = data;
}
)
this.myForm.reset();
this.submitted = false;
}
}
deletetodo(id: any) {
console.log(id);
this.httpService.deleteTodo(id).subscribe((data)=>{
this.todoitems = data;
});
}
}
<form [formGroup]="myForm">
<div>
<input formControlName="todoitems" [(ngModel)]="todolist" name="todoitems">
<button type="submit" (click)="addTodo()">Add</button>
<div>
<div *ngIf="submitted && myForm.controls.todoitems.errors">
<div *ngIf="myForm.controls.todoitems.errors.required"> please fill</div>
<div *ngIf="myForm.controls.todoitems.errors.minlength">min 3</div>
</div>
</div>
</div>
<br>
<div>
<table style="width:50%">
<tr *ngFor="let todoitem of todoitems; let i = index" >
<td>{{ todoitem.name }}</td>
<td>
<button (click)="deletetodo(todoitem.id)">Delete</button>
</td>
</tr>
</table>
</div>
</form>
i'm posting my data from frontend and its going to the backend just
fine, but it is not showing on the front end, how do i get data back
correctly and print in frontend
app.post('/api/names', (req, res) => {
let todoitem = {todoitems:req.body.name
};
var sql = `INSERT INTO todolist SET?`;
mysqlConnection.query(sql, todoitem, (err) => {
if (err) throw err;
res.send(200)
})
});
app.get('/api/names', (req, res) => {
mysqlConnection.query('SELECT todoitems FROM todolist', (err, rows, fields) => {
if (!err)
res.send(rows);
else
console.log(err);
})
});
app.get('/api/names', (req, res) => {
var query = 'select id, code, name from Continent'
findTodoItems(query, function(err, results) {
if (err) {
console.log(err)
throw err;
}
res.send(results);
});
});
function findTodoItems(queryString, cb) {
mysqlConnection.query(queryString, function (err, rows, fields) {
cb(err, rows);
});
};

how to get sending data from restAPI after post response in angular 5?

I have a problem with the output of the json object sent from the server, for some reason I can not get and display the message contained in the response from the server. What am I doing wrong? Thanks for any help.
Below is the code for my application.
service :
import { Injectable } from '#angular/core';
import { HttpClient, HttpHeaders, HttpRequest } from '#angular/common/http';
import { User } from './user';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';
import { ResponseObject } from './response-object';
#Injectable()
export class MntApiService {
private mntAPI = 'http://localhost:3000';
constructor(private _http: HttpClient) {
}
getUsers(): Observable<any> {
return this._http.get<any>(this.mntAPI + '/users');
}
addUser(email: string, password: string): Observable<any> {
return this._http.post<any>(this.mntAPI + '/signup', { email, password }, )
.map((response: Response) => response);
}
}
component:
import { Component, OnInit } from '#angular/core';
import { FormGroup, FormBuilder, Validators } from '#angular/forms';
import { HttpErrorResponse, HttpResponse } from '#angular/common/http';
import { Router } from '#angular/router';
import { MntApiService } from '../mnt-api.service';
import { User } from '../user';
import { ResInterceptor } from '../res-interceptor';
#Component({
selector: 'app-signup-page',
templateUrl: './signup-page.component.html',
styleUrls: ['./signup-page.component.scss']
})
export class SignupPageComponent implements OnInit {
users: any = [];
myForm: FormGroup;
response: {
body: {
succes: boolean,
message: string,
status: number
}
};
constructor(
private mntApiService: MntApiService,
private fb: FormBuilder,
public routes: Router) {
}
ngOnInit() {
this.initForm();
}
private initForm(): void {
this.myForm = this.fb.group({
// type: null,
email: [null, [
Validators.required, Validators.email
]],
password: [null, [
Validators.required
]]
});
}
isControlInvalid(controlName: string): boolean {
const control = this.myForm.controls[controlName];
const result: boolean = control.invalid && control.touched;
return result;
}
addUser() {
const val = this.myForm.value;
const controls = this.myForm.controls;
if (this.myForm.invalid) {
Object.keys(controls)
.forEach(controlName => controls[controlName].markAsTouched());
return;
} else {
val.email = val.email.trim();
val.password = val.password.trim();
if (!val.email && !val.password) {
return;
}
this.mntApiService.addUser(val.email, val.password)
.subscribe(user => {
this.users.push(user);
},
response => { this.response = response; });
console.log(this.response);
return;
}
}
}
component.html
<div class="container pt-5">
<form [formGroup]="myForm">
<div class="form-group">
<label for="email">Email address</label>
<small class="form-text text-danger">
{{response?.body.message}}
</small>
<input formControlName="email" type="email" class="form-control" id="email" placeholder="Enter email" autocomplete="email">
<small *ngIf="isControlInvalid('email')" class="form-text text-danger">неправельный формат почты</small>
</div>
<div class="form-group">
<label for="password">Password</label>
<input formControlName="password" type="password" class="form-control" id="password" placeholder="Password"
autocomplete="current-password">
<small *ngIf="isControlInvalid('password')" class="form-text text-danger">это поле не может быть пустым</small>
</div>
<button (click)="addUser()" class="btn btn-primary">Submit
</button>
</form>
</div>
and my node server code:
app.post('/signup', (req, res) => {
let sql = 'SELECT email FROM users WHERE email = ?';
let emailBody = [req.body.email];
config.query(sql, emailBody, (err, userEmail) => {
const errResponse = {
sacces: false,
message: 'Почта занята'
};
const rightResponse = {
'sacces': true,
'message': 'Пользователь создан',
'status': 201
};
if (userEmail.length < 0) {
res.status(409).send(errResponse);
console.log('mail exist!!!!');
return;
} else {
bcrypt.hash(req.body.password, 10, (err, hash) => {
if (err) {
return res.status(500).json({
error: err
});
} else {
let sql = 'INSERT INTO users ( email, password) VALUES ( ?, ?)';
let email = req.body.email;
let password = hash;
let body = [email, password];
config.query(sql, body, (err) => {
if (err) {
res.json({
"message": 'SQL Error'
});
} else {
//res.sendStatus(201);
res.status(201).send(rightResponse);
// res.status(201).json({
// 'message': "Спасибо за регестрацию"
// });
console.log('User created');
return;
}
});
}
});
}
});
});
please help who can, I'm a novice developer .
This is part of your code
this.mntApiService.addUser(val.email, val.password)
.subscribe(user => {
this.users.push(user);
},
response => { this.response = response; });
What you are doing here it that you are passing the subscribe method 2 parameters.
The first parameter is this function
user => {
this.users.push(user);
}
The second parameter is this function
response => { this.response = response; }
The function you pass to subscribe as second parameter gets executed when an error occurs, which I guess is not what you want.
Probably an implementation like this should do the trick for you
this.mntApiService.addUser(val.email, val.password)
.subscribe(response => {
response => { this.response = response; });
// this.users.push(user); CHECK THIS LINE - YOU ARE NOT RECEIVING A USER FROM THE SERVER BUT A MESSAGE
};

Resources