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 :)
Related
I want to edit and show value in form when user is editing but its not working. Angular frontend is capturing the correct route but data is not getting fetched from backend and no api is getting called. The content is not shown on browser. I'm attatching the git repository link also in case if you want to take a look https://github.com/tridibc2/blog-admin-mean. The route to do the editing is http://localhost:4200/admin/blog and click on edit button. Below I'm attaching edit-blog.component.html code
<h3>Edit this blog</h3>
<div class="row" style="text-align:left">
<div class="col-md-12">
<form #createBlogForm="ngForm" (ngSubmit)="editThisBlog()">
<div class="form-group">
<label>Blog Title</label>
<input type="text" name="blogTitle" [(ngModel)]="currentBlog.title" #title="ngModel" class="form-control" placeholder="Enter blog Title"
required>
</div>
<div [hidden]="title.valid || title.pristine" class="alert alert-danger">
Blog Title is required
</div>
<div class="form-group">
<label>Description</label>
<input type="text" name="blogDescription" [(ngModel)]="currentBlog.description" #description="ngModel" class="form-control" placeholder="Enter Description"
required>
</div>
<div class="form-group">
<label>Enter the blog body</label>
<textarea name="blogBodyHtml" [(ngModel)]="currentBlog.bodyHtml" #bodyHtml="ngModel" class="form-control" rows="3" required></textarea>
</div>
<div class="form-group">
<label>Category</label>
<select [(ngModel)]="currentBlog.category" #category="ngModel" name="blogCategory" class="form-control" id="category" required>
<option *ngFor="let category of possibleCategories" [value]="category">{{category}}</option>
</select>
</div>
<button type="submit" class="btn btn-default" [disabled]="!createBlogForm.form.valid">Edit the blog</button>
</form>
</div>
</div>
</div>
edit-blog.component.ts
import { ActivatedRoute, Router } from '#angular/router';
import { BlogpostService } from 'src/app/client/blogpost.service';
import { ToastsManager } from 'ng6-toastr/ng2-toastr';
import { FormGroup, FormBuilder } from '#angular/forms';
#Component({
selector: 'app-edit-blog',
templateUrl: './edit-blog.component.html',
styleUrls: ['./edit-blog.component.css']
})
export class EditBlogComponent implements OnInit {
public currentBlog;
public possibleCategories = ["Comedy", "Action", "Drama", "Technology","Cooking","Travel"];
constructor(private blogpostService: BlogpostService, private _route: ActivatedRoute, private router: Router, public toastr: ToastsManager) { }
ngOnInit() {
console.log("blogedit ngOnInIt called");
let myBlogId = this._route.snapshot.paramMap.get('blogId');
console.log(myBlogId);
this.blogpostService.getSingleBlogInformation(myBlogId).subscribe(
data =>{
console.log(data);
this.currentBlog = data;
console.log(this.currentBlog);
},
error =>{
console.log("some error occured");
console.log(error.errorMessage);
})
}
public editThisBlog(): any {
this.blogpostService.editBlog(this.currentBlog.blogId, this.currentBlog).subscribe(
data =>{
console.log(data);
this.toastr.success('Blog Edited Successfully.', 'Success!');
setTimeout(() =>{
this.router.navigate(['/blog', this.currentBlog.blogId]);
}, 1000)
},
error =>{
console.log(error);
console.log(error.errorMessage);
this.toastr.error('Some Error Occured.', 'Oops!');
}
)
}
}
service code
import { catchError } from 'rxjs/operators';
import { HttpClient, HttpErrorResponse, HttpBackend, HttpParams } from '#angular/common/http';
import { Observable } from 'rxjs/Observable';
import { throwError } from 'rxjs';
import 'rxjs/add/operator/catch';
import 'rxjs/add/operator/do';
#Injectable({
providedIn: 'root'
})
export class BlogpostService {
public allBlogs;
public currentBlog;
errorData: {};
isLoggedIn = false;
public baseUrl = 'http://localhost:4000/api/v1/blogs';
constructor(private _http:HttpClient, private handler: HttpBackend) { }
public getAllBlogs(): any {
let myResponse = this._http.get(this.baseUrl + '/all').pipe(
catchError(this.handleError)
);
console.log(myResponse);
return myResponse;
}
public getSingleBlogInformation(currentBlogId): any {
let myResponse = this._http.get(this.baseUrl + '/view/' + currentBlogId).pipe(
catchError(this.handleError)
);
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 + '/edit' + '/' + blogId, blogData);
return myResponse;
}
public getUserInfoFromLocalStorage: any = () =>{
return JSON.parse(localStorage.getItem('userInfo'));
}
public setUserInfoInLocalStorage: any = (data) =>{
localStorage.setItem('userInfo', JSON.stringify(data))
}
public signinFunction(data): Observable<any>{
const params = new HttpParams()
.set('email', data.email)
.set('password', data.password)
return this._http.post(`${this.baseUrl}/login`, params);
}
private handleError(error: HttpErrorResponse) {
if (error.error instanceof ErrorEvent) {
// A client-side or network error occurred. Handle it accordingly.
console.error('An error occurred:', error.error.message);
} else {
// The backend returned an unsuccessful response code.
// The response body may contain clues as to what went wrong,
console.error(`Backend returned code ${error.status}, ` + `body was: ${error.error}`);
}
// return an observable with a user-facing error message
this.errorData = {
errorTitle: 'Oops! Request for document failed',
errorDesc: 'Something bad happened. Please try again later.'
};
return throwError(this.errorData);
}
}
node controller code for the edit api
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 {
result.views += 1;
result.save(function (err, result) {
if (err) {
console.log(err)
res.send(err)
}
else {
console.log("Blog updated successfully")
res.send(result)
}
});// end result
}
});
}
route
app.put(baseUrl+'/edit/:blogId',blogController.editBlog);
the data object is like this
{"title":"Blog Title 2 Custom","description":"Blog description 2 Custom","bodyHtml":"<h3>Heading of the body CUSTOM</h3><p>This is the first blog data getting uploaded n blog project</p>","views":5,"isPublished":true,"category":"tech","author":"Decardo","tags":["english movies, action movies, comedy"],"_id":"5e1120d223416207d8ae5e1b","blogId":"nbfO8hJp","created":"2020-01-04T23:33:38.000Z","lastModified":"2020-01-04T23:33:38.000Z","__v":0}
Just fix the path of edit button like this:
<a [routerLink]="['/admin/edit', blog.blogId]" class="btn btn-info btn-sm">Edit</a>
Forward on the API part your edit method is incomplete as you are not updating the object that you find with the new values.
let editBlog = (req, res) => {
const data = req.body;
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 {
for (let key in data) {
result[key] = data[key];
}
result.views += 1;
result.save(function (err, result) {
if (err) {
console.log(err)
res.send(err)
}
else {
console.log("Blog updated successfully")
res.send(result)
}
});// end result
}
});
};
To edit the Blog's info you are calling editBlog method from blogpost service passing into it an id (blogId) and a body (blogData). So on the server side what you get is an id and body which is the update data. You can get the body from request so req.body. What you missed is to update actually the object you found, and that's why i made a loop to update the values of Blog object with the new values from req.body, and only once updated you save it. Obviously there are other ways to update the object we want to modify.
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);
});
};
I am currently learning node.js and creating test application using angular so in that i need to retrieve data stored in Mongodb below i have written query to get mongodb data using node.js but unable to get data so what is the exact procedure for changes need to be done in query.
In Html(component in angular):
<div class="col-md-12">
<div class="container">
<table class="table mar-top-20">
<thead class="thead-dark">
<tr>
<th>Date</th>
<th>Client Name</th>
<th>Client Email</th>
<th>Client Password</th>
<th>Action/Status</th>
</tr>
</thead>
<tbody>
<tr>
<td>{{userDetails.added_on}}</td>
<td>{{userDetails.username}}</td>
<td>{{userDetails.uemail}}</td>
<td>{{userDetails.upassword}}</td>
<td>Show Detail</td>
</tr>
</tbody>
</table>
</div>
</div>
In TS file(component in angular):
import { Component, OnInit } from '#angular/core';
import { FormBuilder, FormGroup , Validators } from '#angular/forms';
import { DataService } from '../../../services/data.service';
import { AccountService } from '../../../services/account.service';
import { Router } from '#angular/router';
// import { Client } from '../../../client';
#Component({
selector: 'app-manage-users',
templateUrl: './manage-users.component.html',
styleUrls: ['./manage-users.component.css'],
})
export class ManageUsersComponent implements OnInit {
userDetails: any;
rForm: FormGroup;
post:any;
username: String = '';
uemail: String = '';
upassword: String = '';
constructor(private router: Router,private fb:FormBuilder,private dataService: DataService, private accountService: AccountService) {
this.rForm = fb.group({
'username':['', Validators.required],
'uemail':['', Validators.required],
'upassword': [ '', Validators.required ]
});
}
ngOnInit() {
//Getting user using userId
this.accountService.getUser({ userId: localStorage.getItem('userId') }).subscribe(
response => {
console.log(response);
this.userDetails = JSON.parse(response);
},
err => {
console.error('User Not found');
})
}
}
accountService.ts:
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import { DataService } from './data.service';
#Injectable()
export class AccountService {
public apiPath: string;//Api URL where we need to send our data & perform related operations
constructor(ds: DataService, private http: HttpClient) {
this.apiPath = ds.apiPath;
}
getUser(user) {//Getting User with userId
return this.http.post(this.apiPath + 'user/getUser', user, { responseType: 'text' });
}
}
UserController.js:
userRouter.post('/getUser', (req, res) => {
var user = {
_id: req.body.userId,
};
Collections.user.findOne(user, function (err, result) {
if (err) return res.status(500).send("There was a problem finding the user");
if (result) {
res.status(200).send(result);
} else {
res.status(500).send("User Not Found with Details: " + JSON.stringify(user));
}
});
});
My database name is testdb and collection name is users
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
};
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.