I have a service which has some data stored like this and functions that push data to it:
service.ts
export class SongsService {
albumsChanged = new Subject();
//Define future album name and songs list
newAlbumName:any;
newSongs:any;
newAlbumID:any;
// New album object
albumData:{name: string, songs:Array<string>};
albums = [
{
name: 'One album',
songs: [
'song1 Album 1',
'song2 Album 1',
'song3 Album 1',
]
}];
albumSongs(albumID){
return this.http.get('http://api.musicgraph.com/api/v2/album/'+
albumID +'/tracks?"+ api_key + "&limit=30").map(
(res:Response) => {
const songData = res.json();
// func to get all tracks
var tracks = songData.data.map(a => a.title);
// Function to filter repeated songs
var uTracks = tracks.filter(function(elem, index, self) {
return index == self.indexOf(elem);
});
return this.allTracks= uTracks;
}
);
}
// .subscribe(album => {console.log(album)}) returns []
newAlbum(name:string){
name = name.replace(/ /g, '+');
var albumID= '';
this.http.
get('http://api.musicgraph.com/api/v2/album/suggest?'
api_key + '&limit=2&prefix=' + name)
.subscribe(
( res:Response) => {
var rawData = res.json();
// console.log(rawData);
var albumName:string = rawData.data[0].title;
albumID = rawData.data[0].id;
this.albumSongs(albumID).subscribe(
songs => {
this.newSongs = songs;
console.log("And this are the songs in newAlbum = " + this.newSongs );
this.albumData = {
name:albumName,
songs:this.newSongs
};
this.albums.push(this.albumData)
this.albumsChanged.next(this.albums.slice())
}
);
}
);
this.albumsChanged.next(this.albums.slice());
}
newAlbum (name:string) {
//function that gets album name from api
this.albums.push(albumObj);
this.albumsChanged.next(this.albums.slice());
}
I have set my app.component to run an init function as a seed:
import { Component, ViewChild, ElementRef, OnInit } from '#angular/core';
import { SongsComponent } from './songs/songs.component';
import { Router } from '#angular/router';
import { SongsService } from './songs.service';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
providers: []
})
export class AppComponent {
albums:any = [];
constructor(private songsService: SongsService){
};
ngOnInit() {
this.songsService.init()
}
}
App.module
const appRoutes: Routes =[
{path: '', component: AlbumsComponent},
{path: ':album', component: SongsComponent},
];
#NgModule({
declarations: [
SongsComponent,
AppComponent,
AlbumsComponent
],
imports: [
BrowserModule,
FormsModule,
RouterModule.forRoot(appRoutes),
HttpModule
],
providers: [SongsService],
bootstrap: [AppComponent]
})
export class AppModule {}
When I console.log(this.albums) in the next component it only has the seed I hard coded on service.ts.
Albums.component.ts
#Component({
selector: 'app-albums',
templateUrl: './albums.component.html',
styleUrls: ['./albums.component.css'],
providers: []
})
export class AlbumsComponent {
#ViewChild('albumInput') albumInput: ElementRef;
#ViewChild('deleteIcon') deleteIcon: ElementRef;
private albums:{name: string, songs:Array<string>}[] = [];
private subscription: Subscription;
constructor(private songsService: SongsService,
private router: Router){};
ngOnInit() {
this.albums = this.songsService.albums;
this.subscription = this.songsService.albumsChanged
.subscribe(
(albums:{name: string, songs:Array<string>}[]) => {
this.albums = albums;
});
console.log(this.albums);
}
albumslog(){
console.log(this.albums)
}
// albumSongs(){
// this.router.navigate([])
// }
deleteAlbum(indexOfAlbum){
console.log(this);
console.log(indexOfAlbum);
this.songsService.albums.splice(indexOfAlbum,1);
addAlbum(albumName){
this.songsService.newAlbum(albumName);
console.log(this.songsService.albums);
And songs.components:
#Component({
selector: 'app-songs',
templateUrl: './songs.component.html',
styleUrls: ['./songs.component.css'],
providers: []
})
export class SongsComponent implements OnInit {
private subscription: Subscription;
private albums:any;
private album:any;
private songs:Array<string>;
private albumIndex:string;
constructor(private songsService: SongsService,
private router: Router,
private route: ActivatedRoute){};
ngOnInit() {
var albumIndex = +this.route.snapshot.params['album'];
console.log(albumIndex);
this.albums = this.songsService.albums;
this.subscription = this.songsService.albumsChanged
.subscribe(
(albums:{name: string, songs:Array<string>}[]) => {
this.albums = albums;
this.songs = this.getAlbum(albumIndex);
});
console.log(this.albums);
this.getAlbum(albumIndex);
// console.log(this.songsService.getAlbum("Asà en el Cielo Como en la Selva"))
console.log(this.songs);
}
getAlbum(index: number){
return this.album = this.albums.splice(index)
Therefore, when I go to another route my service.albums from my service is empty, how can I keep this data over many routes?
Related
Have an observable being returned from my service.ts as shown here:
import { Injectable, ErrorHandler } from '#angular/core';
import { HttpClient, HttpErrorResponse, HttpHeaders } from
'#angular/common/http'
import { Observable } from 'rxjs';
import { catchError, tap } from 'rxjs/operators';
import { PokeResponse } from '../PokeResponse';
#Injectable({
providedIn: 'root'
})
export class PokeApiService {
private url = "https://pokemon-go1.p.rapidapi.com/pokemon_stats.json";
constructor(private http:HttpClient) { }
getPokeData(): Observable<PokeResponse> {
return this.http.get<PokeResponse>(this.url,
{
headers : new HttpHeaders({
'x-rapidapi-key': 'a6cef4cbcamsh05b29346394d4a4p1bafacjsn2a92406ac103'
})
})
.pipe(
tap(data => console.log('Pokedata/Error' + JSON.stringify(data))
),
catchError(this.handleError)
);
}
private handleError(err:HttpErrorResponse) {
console.log('PokemonService: ' + err.message);
return Observable.throw(err.message);
}
}
This is my response:
export interface PokeResponse{
list:results[];
results:{
pokemon_id:number;
pokemon_name:string;
base_attack:number;
base_defense:number;
base_stamina:number;
}[];
}
export interface results{
pokemon_id:number;
pokemon_name:string;
base_attack:number;
base_defense:number;
base_stamina:number;
}
export class Pokemon implements results{
pokemon_id:number;
pokemon_name:string;
base_attack:number;
base_defense:number;
base_stamina:number;
constructor(_id:number, _name:string, _atk:number, _def:number, _stam:number) {
_id = this.pokemon_id;
_name = this.pokemon_name;
_atk = this.base_attack;
_def = this.base_defense;
_stam = this.base_stamina;
}
}
And this is my component.ts:
import { Component, OnInit } from '#angular/core';
import { PokeApiService } from 'src/app/services/poke-api.service';
import { PokeResponse, results, Pokemon } from 'src/app/PokeResponse';
import { Observable } from 'rxjs';
#Component({
selector: 'app-list-pokemon',
templateUrl: './list-pokemon.component.html',
styleUrls: ['./list-pokemon.component.css']
})
export class ListPokemonComponent implements OnInit {
constructor(private pokeService: PokeApiService) { }
ngOnInit(): void {
this.getPokeDetails();
}
pokeData:PokeResponse;
errorMessage:any;
pokeArray:results;
getPokeDetails() : boolean {
this.pokeService.getPokeData().subscribe(
pokeData => {
this.pokeData=pokeData;
console.table(pokeData);
},
error => this.errorMessage = <any>error
);
return false;
}
}
In my console I'm getting back a console.table of my observable like this
I'm trying to filter out the names of Pokemon which are the same as others, which could also be achieved by just filtering out any of the pokemon_ids as all the stats match regardless of the type.
So far I've tried:
console.log(this.pokeArray);,
using [...Set()], forEach(), and Array.from()
Any help or suggestions on how I can make this question any clearer would be greatly appreciated.
Try this, using filter:
// list-pokemon.component.ts
export class ListPokemonComponent implements OnInit {
uniqueListPoke = [];
flags = {};
constructor(private pokeService: PokeApiService) { }
ngOnInit(): void {
this.getPokeDetails();
}
pokeData:PokeResponse;
errorMessage:any;
pokeArray:results;
getPokeDetails() : boolean {
this.pokeService.getPokeData().subscribe(
pokeData => {
this.uniqueListPoke = pokeData.filter((entry) => {
if (this.flags[entry.pokemon_name]) {
// console.log('flags', false);
return false;
}
this.flags[entry.pokemon_name] = true;
return true;
});
console.log(JSON.stringify(this.uniqueListPoke));
},
error => this.errorMessage = <any>error
);
return false;
}
}
The working example:
https://stackblitz.com/edit/angular-distinct-poke?file=src/app/hello.component.ts
*I'm making a angular project (version 6+).
I want to transfer array parameter, using routing.
*
const routes: Routes = [
{
path: 'books',
component: BookComponent
}
,
{
path: 'books/:id',
component: BookDetailComponent
},
...
There are two ways you can use,
Method 1:
HTML
<a routerLinkActive="active" [routerLink]="['/home', userIDs.join()]">Home</a>
TS:
userIDs: Array<number> = [1, 3, 4];
Home component typescript:
export class HomeViewComponent implements OnInit {
userIDs: Array<number> = [];
constructor(private router: ActivatedRoute) { }
ngOnInit() {
this.router.params.subscribe(params => {
this.userIDs = params['ids'].split(',');
});
}
}
Router Module:
path: 'home/:ids', component: HomeViewComponent }
Method 2 (Using queryParams):
You don't need to add anything into router module as we are doing in above method.
HTML
<a routerLinkActive="active" [routerLink]="['/home']" [queryParams]="{ids: userIDs}">Home</a>
TS
userIDs: Array<number> = [1, 3, 4];
Home component typescript:
export class HomeViewComponent implements OnInit {
userIDs: Array<number> = [];
constructor(private router: ActivatedRoute) { }
ngOnInit() {
this.router.queryParams.subscribe(p => {
this.userIDs = p.ids;
});
}
}
In html
send data
here first You will import the activated route like following.
import { ActivatedRoute } from '#angular/router';
and also in construction
construction(private _routes:ActivatedRoute) { }
In====== ngOnInit( this._route.params.subscribe(params => {
this.id=param['id'];
)
I would like to add in an array of objects, but it does not work: Can not set property '0' of undefined
I try to put in this.positions [0] = the PositionMap object
I have decreased the size of the code for better readability, but the rest works
Here is my code:
import { Component, ViewChild, ElementRef } from '#angular/core';
import { NavController } from 'ionic-angular';
import { FormBuilder, FormGroup, Validators } from '#angular/forms';
import { Geolocation } from 'ionic-native';
declare var google;
#Component({
selector: 'page-home',
templateUrl: 'home.html'
})
export class HomePage {
positions: PositionMap[] = [];
#ViewChild('map') mapElement: ElementRef;
constructor(public navCtrl: NavController) {
this.positions = [];
}
ionViewDidLoad(){
this.loadMap();
this.autocomplete();
}
autocomplete() {
autocompleteDepart.addListener('place_changed', function() {
var place = autocompleteDepart.getPlace();
let tmpPosition = new PositionMap(place.geometry.location.lat(), place.geometry.location.lng());
this.positions[0] = (tmpPosition);
return;
});
}
}
export class PositionMap {
latitude: number;
longitude: number;
constructor(_latitude: number, _longitude: number) {
this.latitude = _latitude;
this.longitude = _longitude;
}
}
My table is well declared in the class and in the constructor, but yet is not known in the function.
You're using this from a callback function. This callback function must first be bound to this. The easiest way is to use an arrow function:
autocompleteDepart.addListener('place_changed', () => {
...
});
I'm writing a simple web application using Angular 2 written in TypeScript. MongoDB is my database on a Mongoose framework while running on a Node server on an Express framework. My MongoDB and Node code is written in vanilla JS.
Now, I created a Mongoose model for a Country as following:
"use strict";
const Schema = require('mongoose').Schema,
db = require('../../config/database');
let countrySchema = new Schema({
countryName: { type: String, index : { unique : true } }
});
let Country = db.model('Country', countrySchema);
module.exports = Country;
Now, Country is what I want my object to be. In my app component, I have:
import { Component } from '#angular/core';
import { CountryService } from '../services/country.service';
import { Country } from '../models/country.model';
#Component({
selector: 'my-app',
templateUrl: 'app/views/app.component.html',
providers: [ CountryService ]
})
export class AppComponent {
originCountries: Country[];
destinationCountries: Country[];
constructor(private countryService: CountryService) { };
ngOnInit() {
this.getCountries();
}
getCountries() {
this.countryService.getCountries()
.then(countries => {
this.originCountries = countries;
this.destinationCountries = countries;
});
}
}
See how originCountries and destinationCountries should be arrays of Countries? I can't just import Country from the Country model (even though it sounded right in my head at the time).
What is the best way to create a country class that is based on the Mongoose model?
You use an interface like this ICountry:
export interface ICountry {
_id: string;
name: string;
}
You can now use this interface in your mongoose setup:
import mongoose = require('mongoose');
import { ICountry } from './interfaces';
var _schema: mongoose.Schema = new mongoose.Schema({
name: { type: String, required: true, index: { unique: true } }
});
type CountryType = ICountry & mongoose.Document;
var _model = mongoose.model <CountryType> ('Country', _schema);
export class Country {
static getAll(): Promise<Array<ICountry>> {
return new Promise<ICountry> ((resolve, reject) => {
_model.find((err, counties) => {
err ? reject(err) : resolve(counties);
});
});
}
}
And the route setup:
var router = express.Router();
router.get('/api/countries', (req, res) => {
Country.getAll().then(c => {
return res.json(c);
});
});
And implement it in your Angular application, if you need some methods or just import the interface direct in your service class:
import { ICountry } from '../../interfaces';
...
countries: Array<ICountry>
This is how I do it in my project:
In my schema file:
///<reference path="../typings/mongoose/mongoose.d.ts"/>
import * as mongoose from 'mongoose';
var UserSchema = new mongoose.Schema({
name: String,
// ...
});
export interface IUser extends mongoose.Document {
_id: string;
name: string;
// ...
}
export interface IUserModel extends mongoose.Model<IUser> { }
export var User: IUserModel = <IUserModel>mongoose.model<IUser>('User', UserSchema);
In the server side code:
import {User, IUser, IUserModel} from '../schemas/user.schema';
// ...
User.findOne({ ... });
In the client side code I now can use the IUser interface:
import {IUser} from '../---/schemas/user.schema';
// ...
userCache: Array<IUser>;
I need to modify my code where loading detail category will first look whether it is not already loaded in the statement, and if not then detail loads. Thanks for help!
Constructor of CategoryProvider:
private _obServers = {
'categoryList': undefined,
'category': undefined,
'idCategory': new Subject<Number>()
};
constructor(){
this.categories = new Observable(observer => this._obServers.categoryList = observer).share();
this._categoryObservable = this.categories
.combineLatest(this._obServers.idCategory, (categories, idCategory) => {
return categories.filter(category => category.id === idCategory)[0];
})
.distinctUntilChanged((oldCategory, newCategory) => {
return oldCategory.id === newCategory.id;
});
}
CategoryList:
loadCategories(search?:string):void{
this._http
.get('/services/category/list?search=' + search)
.map(res => res.json())
.subscribe(data => {
this._obServers.categoryList.next(this.createCategoryEntities(data));
});
}
CategoryDetail:
loadCategory(categoryId:number){
this._obServers.idCategory.next(categoryId);
//If category not loaded I need to load it
}
I have followed this way https://github.com/JonatanSCS/Angular-2-Tutorial/blob/master/node_modules/rxjs/src/add/observable/combineLatest.ts
import { Component, Injectable, Inject, provide } from '#angular/core';
import { HTTP_PROVIDERS } from '#angular/http';
import { Observable } from 'rxjs/Observable';
import { combineLatestStatic } from 'rxjs/operator/combineLatest.js';
import { MessageApi } from '../providers/lb-service/lb-services.provider'
import { EstimatesService } from './estimates.service';
#Component({
pipes: [TranslatePipe],
})
#Injectable()
export class InvoiceService {
constructor(private _message:MessageApi,
#Inject(EstimatesService) _estimates:EstimatesService) {
this._message = _message;
this._estimates = _estimates;
Observable.combineLatest = combineLatestStatic;
declare module 'rxjs/Observable' {
namespace Observable {
export let combineLatest: typeof combineLatestStatic;
}
}
Observable.combineLatest(
this._estimates.getEstimates(),
this._message.findOne({
where: {
moduleTag: 'monthlyStat',
'dynamic.date': "2016-07-01" //new Date
},
fields: {
dynamic: true
}
}),this._message.findOne({
where: {
moduleTag: 'areaPriceSE1',
'dynamic.date': ''
},
fields: {
dynamic: true
}
})
).subscribe(res => console.log("observable", res));