save and fetch on firebase in angular is not working - javascript

Why my movie component is not updating after fetching the data. Also not saving the data if I have added a new movie or made changes in existing movies.
It is just saving and fetching the data which is written in movie.service.ts file. Also the fetched data is not rendering on the movie component.
Data-storage.service
import { Injectable } from '#angular/core';
import { MovieService } from '../movies/movies.service';
import { HttpClient, HttpHeaders, HttpParams, HttpRequest } from '#angular/common/http';
import { Movie } from '../movies/movie.model';
import { Observable} from 'rxjs';
import { map } from 'rxjs/operators';
// import 'rxjs/Rx';
// import 'rxjs/Rx';
#Injectable({
providedIn: 'root'
})
export class DataStorageService {
constructor(private httpClient: HttpClient,
private movieService: MovieService,) { }
storeMovies(): Observable<any> {
const req = new HttpRequest('PUT', 'https://moviepedia-4211a.firebaseio.com/movies.json', this.movieService.getMovies(), {reportProgress: true});
return this.httpClient.request(req);
}
getMovies() {
this.httpClient.get<Movie[]>('https://moviepedia-4211a.firebaseio.com/movies.json', {
observe: 'body',
responseType: 'json'
})
.pipe(map(
(movies) => {
console.log(movies);
return movies;
}
))
.subscribe(
(movies: Movie[]) => {
this.movieService.setMovies(movies);
}
);
}
}
movie.service.ts :
import { Injectable } from '#angular/core';
import {Subject} from 'rxjs';
import { Movie } from './movie.model';
#Injectable()
export class MovieService {
moviesChanged = new Subject<Movie[]>();
private movies: Movie[] = [
new Movie(
'Movie test', 'Movie details', 'https://s18672.pcdn.co/wp-content/uploads/2018/01/Movie-300x200.jpg'
),
new Movie(
'Movie test 2', 'Movie details 2', 'https://s18672.pcdn.co/wp-content/uploads/2018/01/Movie-300x200.jpg'
),
new Movie(
'Movie test 2', 'Movie details 3', 'https://s18672.pcdn.co/wp-content/uploads/2018/01/Movie-300x200.jpg'
)
];
constructor(){}
getMovie(index: number) {
return this.movies[index];
}
getMovies() {
return this.movies.slice();
}
addMovie(movie: Movie) {
this.movies.push(movie);
this.moviesChanged.next(this.movies.slice());
}
updateMovie(index: number, newMovie: Movie) {
this.movies[index] = newMovie;
this.moviesChanged.next(this.movies.slice());
}
deleteMovie(index: number) {
this.movies.splice(index, 1);
this.moviesChanged.next(this.movies.slice());
}
setMovies(movies: Movie[]) {
this.movies = movies;
this.moviesChanged.next(this.movies.slice());
}
}
movie.model.ts
export class Movie {
public name: string;
public description: string;
public imagePath: string;
constructor(name: string, description: string, imagePath: string) {
this.name = name;
this.description = description;
this.imagePath = imagePath;
}
}
movie.component :
import { Component, OnInit, EventEmitter, Output, OnDestroy } from '#angular/core';
import { Movie } from '../movie.model'
import { MovieService } from '../movies.service';
import { Router, ActivatedRoute } from '#angular/router';
import { Subscription } from 'rxjs';
#Component({
selector: 'app-movie-list',
templateUrl: './movie-list.component.html',
styleUrls: ['./movie-list.component.css']
})
export class MovieListComponent implements OnInit, OnDestroy {
subscription: Subscription;
movies: Movie[] = [];
constructor(private movieService: MovieService,
private router: Router,
private route: ActivatedRoute) { }
ngOnInit() {
this.subscription = this.movieService.moviesChanged
.subscribe(
(movies: Movie[]) => {
this.movies = movies;
}
);
this.movies = this.movieService.getMovies();
}
onNewMovie() {
this.router.navigate(['new'], {relativeTo: this.route});
}
ngOnDestroy() {
this.subscription.unsubscribe();
}
}
What can I do save and fetch data which will render on page.

I think the problem with your PUT request is that the url you used expects json but you are sending Movie object. you should send and receive json to this url.
wish it helps ...

Related

Firebase action.payload returns id, but data is undefined

In my Firebase Cloud Firestore, I have a collection of galleries, and each gallery document has a subcollection of images.
screnshoot Cloud Firestore
screnshoot Cloud Firestore
I was able to retrieve and display the galleries and the images inside each gallery, but when I try to retrieve the single image document, I get only the ID and the data is undefined (so it's like the name and the url of the image don't exist)
Here my image.service.ts
import { Injectable } from '#angular/core';
import {
AngularFirestore,
AngularFirestoreCollection,
AngularFirestoreDocument,
} from '#angular/fire/firestore';
import { AngularFireStorage } from '#angular/fire/storage';
import { finalize } from 'rxjs/operators';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { Image } from '../models/Image';
#Injectable({
providedIn: 'root',
})
export class ImageService {
images: Observable<Image[]>;
image: Observable<any>;
imageCollection: AngularFirestoreCollection<Image>;
imageDoc: AngularFirestoreDocument<Image>;
url!: string;
name: string;
constructor(
private afs: AngularFirestore,
private storage: AngularFireStorage
) {}
getGalleryImages(id: string | any): Observable<Image[]> {
this.imageCollection = this.afs.collection(`galleries/${id}/images`);
this.images = this.imageCollection.snapshotChanges().pipe(
map((changes) => {
return changes.map((action) => {
const data = action.payload.doc.data() as Image;
console.log(data);
const id = action.payload.doc.id;
return { id, ...data };
});
})
);
return this.images;
}
getImageDetail(id: string | any) {
this.imageDoc = this.afs.doc(`/images/${id}`);
this.image = this.imageDoc.snapshotChanges().pipe(
map((action) => {
const data = action.payload.data();
const id = action.payload.id;
console.log(data, id);
return { id, ...data };
})
);
return this.image;
}
}
Here my image-detail.component.ts
import { Component, OnInit } from '#angular/core';
import {
AngularFirestore,
AngularFirestoreCollection,
AngularFirestoreDocument,
} from '#angular/fire/firestore';
import { Router, ActivatedRoute } from '#angular/router';
import { ImageService } from '../../../services/image.service';
import { Image } from '../../../models/Image';
#Component({
selector: 'app-image-detail',
templateUrl: './image-detail.component.html',
styleUrls: ['./image-detail.component.css'],
})
export class ImageDetailComponent implements OnInit {
image: Image | any;
id: string;
name: string | any;
url: string;
constructor(
private route: ActivatedRoute,
private imageService: ImageService,
private afs: AngularFirestore
) {}
ngOnInit(): void {
this.getImage();
}
getImage() {
const id = this.route.snapshot.paramMap.get('id');
this.imageService.getImageDetail(id).subscribe((image) => {
this.image = image;
console.log(image);
return image;
});
}
}
I even tried this but the result is the same
getImageDetail(id: string | any): Observable<Image[]> {
this.imageDoc = this.afs.doc(`/images/${id}`);
this.image = this.imageDoc.snapshotChanges().pipe(
map((action) => {
const data = action.payload.data() as Image
const id = action.payload.id;
console.log(data, id);
return { id, ...data };
})
);
return this.image;
}
Someone is able to tell me what I'm doing wrong?
The two ids must be different:
-the first one should be the id of the gallery doc and
-the second one should be the id of the image doc.
this.imageDoc = this.afs.doc(`/galleries/${galleryId}/images/${id}`);

Cannot read property 'toLowerCase' of undefined in angular when filtering products

I am having this problem in component Type { data: Product[]; id: string; }[]' is not assignable to type 'Product[].
Type { data: Product[]; id: string; } is missing the following properties from type 'Product': title, price, category, imageUrl. When i am trying to assign the values returned from database to
this.filterdProduct = this.Product = products;
In Constructor...
Here is my code: Interface
export interface Product{
title:string;
price:number;
category:string;
imageUrl:string;
}
Service.Ts:
import { Product } from './../../new-products';
import { Observable } from 'rxjs';
import { AngularFireDatabase } from '#angular/fire/database';
import { Injectable } from '#angular/core';
import { map } from 'rxjs/operators';
#Injectable({
providedIn: 'root'
})
export class ProductService {
constructor(private db: AngularFireDatabase){}
create(product){
return this.db.list('/products').push(product);
}
getAll() {
return this.db.list<Product[]>('/products').snapshotChanges()
.pipe(
map(a =>
a.map(
ac => {
const data= ac.payload.val();
const id = ac.key;
// console.log(data);
// console.log(id)
return {data,id}
} )
)
);
}
Component.ts:
import { Product } from './../../new-products';
import { ProductService } from './../Services/product.service';
import { AngularFireDatabase } from '#angular/fire/database';
import { Component, OnInit, OnDestroy } from '#angular/core';
import { Subscription } from 'rxjs';
#Component({
selector: 'app-admin-products',
templateUrl: './admin-products.component.html',
styleUrls: ['./admin-products.component.css']
})
export class AdminProductsComponent implements OnInit, OnDestroy {
Product:Product []= [];
filterdProduct:any = [];
subscription: Subscription;
constructor(private pd:ProductService){
this.subscription = this.pd.getAll().subscribe(products => {
this.filterdProduct = this.Product = products;
})
}
filter(query:string){
this.filterdProduct = (query) ?
this.Product.filter(p => p.title.toLowerCase().includes(query.toLowerCase())) : this.Product;
console.log(query)
}
ngOnInit(){
}
ngOnDestroy(){
this.subscription.unsubscribe();
}
}
The problem is in your getAll function. You are returning an object of type {data, id}. You should return data as your error signifies that you are expected to return an array of Product.
getAll service function return a object, it's not a Product[], but { Product[], id}
ac => {
const data= ac.payload.val();
const id = ac.key;
// console.log(data);
// console.log(id)
return {data,id} <-- Here
} )
It has to return a Product[].
Product:Product []= [];
in AdminProductsComponent field should be renamed to product and not Product as it clashes with interface name so it should be like this -
product: Array<Product> = [];
What is preventing you from using following code?
const data = ac.payload.val();
data.id = ac.key;
return data;

Ionic How to Pass variable to firebase equalTo method

I have already managed to fetch data form firebase.problem is when i'm going to filter data according to the id it doesn't work.
import { Component, OnInit } from '#angular/core';
import { ActivatedRoute } from '#angular/router';
import { AngularFireDatabase, AngularFireList ,} from 'angularfire2/database';
import { Observable } from 'rxjs'
import { query } from '#angular/core/src/render3';
import { Key } from 'protractor';
class postview {
constructor(public title) { }
}
#Component({
selector: 'app-news-view',
templateUrl: './news-view.page.html',
styleUrls: ['./news-view.page.scss'],
})
export class NewsViewPage implements OnInit {
id: string;
public books: AngularFireList<postview[]>;
itemlol: Observable<any>;
posts: Observable<any[]>;
constructor(private route: ActivatedRoute , db: AngularFireDatabase) {
let idp :string = this.id;
this.posts = db.list('Posts' ,ref => {
return ref.orderByChild('Post_Id').equalTo(idp)
}).valueChanges();
// this.itemlol= db.object('Posts').valueChanges();
}
ngOnInit() {
this.id = this.route.snapshot.paramMap.get('id');
console.log(this.id);
console.log(this.posts);
}
}
in the section return ref.orderByChild('Post_Id').equalTo(idp) I need to pass variable in equalTo(). It should change according to the user instructions
Example
equalTo(01)
equalTo(02)
This is my firebase database:
The constructor is called before ngOnInit so the value for this.id will be undefined at the time of the query.
You should get the Parameters in the constructor
this.id = this.route.snapshot.paramMap.get('id');
let idp :string = this.id;
this.posts = db.list('Posts' ,ref => ref.orderByChild('Post_Id').equalTo(idp) ).valueChanges();

Can't retrieve json array from nested json to mat table datasource

As i mentioned in yhe title i have problem with retrieving data from nested json array and assigning it to datasource of mat table . So i hope there a person who faced similar problem as I and can help me. Below I paste my code :
COURSE.SERVICE.ts
import { Injectable } from '#angular/core';
import { environment } from 'src/environments/environment';
import { HttpClient } from '#angular/common/http';
import { Course } from '../_models/course';
import { CourseEnrolment } from '../_models/available_exams/course_enrolment';
#Injectable({
providedIn: 'root'
})
export class CourseService {
baseUrl = environment.apiUrl;
getAllExams(id) {
return this.http.get<CourseEnrolment[]>(this.baseUrl + 'allexams/' + id);
}
AVAILABLE-EXAM.COMPONENT.ts
import { Component, OnInit, ViewChild } from '#angular/core';
import { MatTableDataSource, MatPaginator, MatSort } from '#angular/material';
import { CourseService } from 'src/app/_services/course.service';
import { AuthService } from 'src/app/_services/auth.service';
import { CourseEnrolmentsExam } from 'src/app/_models/courseEnrolmentsExam';
import { Exam } from 'src/app/_models/available_exams/exam';
import { Users } from 'src/app/_models/available_exams/users';
import { CourseEnrolment } from 'src/app/_models/available_exams/course_enrolment';
import { ExamList } from 'src/app/_models/available_exams/exam_list';
import { HttpClient } from '#angular/common/http';
#Component({
selector: 'app-available-exams',
templateUrl: './available-exams.component.html',
styleUrls: ['./available-exams.component.scss']
})
export class AvailableExamsComponent implements OnInit {
dataSourceExam = new MatTableDataSource();
exams: Exam[];
courseEnrolments: CourseEnrolment[];
displayedColumns = [
'id',
'name',
'subject',
'timeLimit',
'examResult'
];
#ViewChild(MatPaginator) paginator: MatPaginator;
#ViewChild(MatSort) sort: MatSort;
constructor(
private courseService: CourseService,
private authService: AuthService,
private httpService: HttpClient
) {}
ngOnInit() {
this.courseService
.getAllExams(this.authService.decodedToken.nameid)
.subscribe(result => {
this.courseEnrolments = result['courseEnrolments'];
console.log(result['courseEnrolments']);
console.log(result['subject']);
console.log(result['courseEnrolments.subject']);
console.log(result['firstName']);
console.log(result['subject']);
console.log(result['courseEnrolments.subject']);
console.log(result['courseEnrolments']);
console.log(result['exams']);
console.log(result['courseEnrolments.subject']);
console.log(result['firstName']);
if (!result) {
return;
}
this.dataSourceExam = new MatTableDataSource(this.courseEnrolments);
this.dataSourceExam.paginator = this.paginator;
this.dataSourceExam.sort = this.sort;
});
}
applyFilter(filterValue: string) {
filterValue = filterValue.trim();
filterValue = filterValue.toLowerCase();
this.dataSourceExam.filter = filterValue;
}
handleClick(event: Event) {
console.log('‘Click’', event);
}
}
Here is my json response from webapi :
try setting the data source like this, add .data after your data source :
this.dataSourceExam.data = result['courseEnrolments'];

Angular 5 component expecting an argument

Im trying a simple profile app, and all the sudden Im getting error TS2554
ERROR in /app/components/profile/profile.component.ts(25,3): error TS2554: Expected 1 arguments, but got 0.
import { Component, OnInit } from '#angular/core';
import { AuthService } from '../../services/auth.service';
import { FlashMessagesService } from 'angular2-flash-messages';
import { Router } from '#angular/router';
#Component({
selector: 'app-profile',
templateUrl: './profile.component.html',
styleUrls: ['./profile.component.css']
})
export class ProfileComponent implements OnInit {
user: Object;
constructor(
private auth: AuthService,
private flashMsg: FlashMessagesService,
private router: Router
) {
}
ngOnInit() {
this.auth.getProfile().subscribe( profile => {
this.user = profile.user;
},
err => {
return false;
});
}
}
auth.service.ts
import { Injectable } from '#angular/core';
import { Http, Headers } from '#angular/http';
import 'rxjs/add/operator/map';
import { tokenNotExpired } from 'angular2-jwt';
#Injectable()
export class AuthService {
authToken: any;
user: any;
constructor(
private http: Http
) {
}
getProfile(user) {
let headers = new Headers();
this.loadToken();
headers.append('Authorization', this.authToken);
headers.append('Content-Type','application/json');
return this.http.get('http://localhost:3000/users/profile', {headers:headers})
.map(res => res.json());
}
loadToken() {
const token = localStorage.getItem('id_token');
this.authToken = token;
}
}
Your getProfile is expecting an argument named user but you are not passing it from the component
You need to pass an argument as follows,
this.auth.getProfile(user).subscribe( profile => {
this.user = profile.user;
},
err => {
return false;
});
or if you don't need an argument , remove it from your service method.

Categories

Resources