Trying to grab the ID param from the URL, however it seems as though I am not defining my params var. Can't see where I am going wrong so maybe someone can help!
Code
import {Component} from 'angular2/core';
import {ROUTER_DIRECTIVES, RouteParams, RouteConfig} from 'angular2/router';
import {OnInit} from 'angular2/core';
#Component({
selector: 'view-movie',
templateUrl : './templates/view-movie.tpl.html',
directives: [ROUTER_DIRECTIVES]
})
export class ViewmovieComponent implements OnInit {
public movie = {};
public id = String;
constructor(params: RouteParams){};
ngOnInit() {
this.id = params.get('id');
}
}
Was suppose to be inserting the params.get in the code block following the constructor function like so
import {Component} from 'angular2/core';
import {ROUTER_DIRECTIVES, RouteParams, RouteConfig} from 'angular2/router';
import {OnInit} from 'angular2/core';
#Component({
selector: 'view-movie',
templateUrl : './templates/view-movie.tpl.html',
directives: [ROUTER_DIRECTIVES]
})
export class ViewmovieComponent implements OnInit {
public movie = {};
public id = String;
constructor(params: RouteParams){
this.id = params.get('id');
}
ngOnInit() {
console.log(this.id);
}
}
simply use either this one
constructor(params: RouteParams){this.id = params.get('id');}
ngOnInit() {console.log(this.id);}
or this one
constructor(private params: RouteParams){}
ngOnInit() {
this.id = this.params.get('id');
console.log(this.id);
}
because if we initialize something without declare type then we have to access within the constructor but if we are going to access outside of the constructor then it will be must to use this
Related
My Problem: I created a CardComponent acts like a card view with css and html and has a constructor.
I want to use it in a cards array (of its type). I use service to store the cards' data.
home comp. is using the service and loop over with ngFor, This is the code.. and below is the error I get...
Is there another way of using this so it will work?
card.component.ts:
import { Component } from '#angular/core';
#Component({
selector: 'app-card',
templateUrl: './card.component.html',
styleUrls: ['./card.component.css']
})
export class CardComponent{
imageSrc : string;
title : string;
constructor(imgSrc : string, title : string) {
this.imageSrc = imgSrc;
this.title = title;
}
ngOnInit(): void {
}
cards.service.ts:
import { CardComponent } from './card/card.component';
export class CardsService{
ctgryCards : CardComponent[] = [
new CardComponent("https://cdn3.iconfinder.com/data/icons/outline-amenities-icon-set/64/Beauty_Saloon-512.png", "Beauty"),
new CardComponent("https://www.pinclipart.com/picdir/middle/391-3917890_get-business-value-from-sustainable-data-electronics-icon.png", "Electronics")
];
getAllCtgryCards(){
return this.ctgryCards.slice();
}
}
home.component.ts:
import { Component, OnInit } from '#angular/core';
import { CardComponent } from '../card/card.component';
import { CardsService } from '../cards.service';
#Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.css']
})
export class HomeComponent implements OnInit {
categoryCards : CardComponent[] = [];
constructor(private cardsServ : CardsService) { }
ngOnInit(): void {
this.categoryCards = this.cardsServ.getAllCtgryCards();
}
}
home.component.html:
<app-card *ngFor = "let card of categoryCards"></app-card>
Error NG2003:
ERROR in src/app/card/card.component.ts:12:15 - error NG2003: No
suitable injection token for parameter 'imgSrc' of class
'CardComponent'. Found string
constructor(imgSrc : string, title : string) {
In card.component.ts:
Update the constructor to be
//import { Inject } from '#angular/core';
constructor(#Inject(String) private imgSrc : string, title : string)
OR
//import { Inject } from '#angular/core';
constructor(#Inject('imgSrc') private imgSrc : string, title : string)
According to https://angular-2-training-book.rangle.io/di/angular2/inject_and_injectable ; #Inject() is a manual mechanism for letting Angular know that a parameter must be injected. #Inject decorator is only needed for injecting primitives.
The primitive types are number, string, boolean, bigint, symbol, null, undefined.
My question would be regarding angular 4, how to get route params, if for example a user gets on your page with, instead of the default url, like for example http://localhost:3000/, to something like http://localhost:3000/user/:id, and to be able to pick up the :id from that url (user has directly entered it in the browser, not navigating through the app).
In the example bellow same component is used, mainly because of needing to catch that id and dispatch other actions, if its present, and that would be it.
I have tried playing around with ActivatedRoute but from what I could tell so far, that only works when navigation throughout the app, from within the app, not in this case, which always returns a null value if that url is directly entered in the browser, it gets redirected to the default / route and that would be it.
Any tips or pointers are much appreciated
app.routing-module.ts
import {hookComponent} from './hook.component';
import {RouterModule, Routes} from '#angular/router';
import {NgModule} from '#angular/core';
export const routes: Routes = [
{
path: '',
component: HookComponent
},
{
path: 'user/:id',
component: HookComponent
}
];
#NgModule({
imports: [RouterModule.forRoot(routes, { enableTracing: true })],
exports: [RouterModule]
})
export class AppRoutingModule {}
hook.component
import {Component, EventEmitter, Input, OnInit, ViewChild} from '#angular/core';
import { ActivatedRoute, ParamMap} from '#angular/router';
#Component({
selector: 'hook',
templateUrl: 'hook.component.html',
styleUrls: ['hook.component.scss']
})
export class HookComponent implements OnDestroy, OnInit {
constructor(private route: ActivatedRoute) {
}
ngOnInit() {
this.sub = this.route.params.subscribe(params => {
console.log('params are', params); //null?
});
}
}
Your way is already ok, but in your example params is an array and you can access to :id by calling params['id']:
this.sub = this.route.params.subscribe(params => {
console.log('params are', params['id']);
});
Here is an working example on stackblitz.
Access current url via Location
public constructor(location:Location) {
let url = location.prepareExternalUrl(location.path());
}
and parse out id from this.
If all you want to do is log the params.id; try using the ActivatedRouteSnapshot like this.
ngOnInit() {
console.log(this.route.snapshot.params.id);
}
If you want to check if the params.id is present, maybe do something like:
import {Component, EventEmitter, Input, OnInit, ViewChild} from '#angular/core';
import { ActivatedRoute, ParamMap} from '#angular/router';
#Component({
selector: 'hook',
templateUrl: 'hook.component.html',
styleUrls: ['hook.component.scss']
})
export class HookComponent implements OnDestroy, OnInit {
hasId: boolean = false;
constructor(private route: ActivatedRoute) {
}
ngOnInit() {
if(this.route.snapshot.params.id !== null)
{
// do magic....
}
}
}
My http-data.service accepts json for output in the component template. Initially, the console shows that the first few calls are given undefined, and the following calls are already taking json, but also if you check the component, then the component shows that the method that outputs the data to the component is called only once and since the data has not yet arrived it writes undefined , But not updated after the arrival of json. Help please understand why? Thank you
My http-data.service:
import {Injectable} from '#angular/core';
import {Http} from '#angular/http';
import {Response} from '#angular/http';
import {Observable} from 'rxjs/Observable';
import 'rxjs/add/operator/map';
#Injectable()
export class HttpService{
constructor(private http: Http) {}
getDataOrganizations(): Observable<any[]>{
return this.http.get('http://localhost:3010/data')
.map((resp:Response)=>{
let dataOrganizations = resp.json().organization;
return dataOrganizations;
});
}
getDataModules(): Observable<any[]> {
return this.http.get('http://localhost:3010/data')
.map((resp: Response)=> {
let dataModules = resp.json().modules;
return dataModules;
});
}
getDataPresets(): Observable<any[]> {
return this.http.get('http://localhost:3010/data')
.map((resp: Response)=> {
let dataPresets = resp.json().presets;
return dataPresets;
});
}
getDataModuleItems(): Observable<any[]> {
return this.http.get('http://localhost:3010/data')
.map((resp: Response)=> {
let dataModuleItems = resp.json().module_items;
return dataModuleItems;
});
}
}
My data-all.service
import { Injectable, EventEmitter } from '#angular/core';
import {Response} from '#angular/http';
import { ModuleModel } from './model-module';
import { ModuleItemsModel } from './model-module-items';
import data from '../data/data-all';
import { PriceService } from './price.service';
import { HttpService } from './http-data.service';
#Injectable()
export class ModuleDataService {
constructor(private priceService: PriceService, private httpService: HttpService){
this.dataMinMaxSum = {minSum: 0, maxSum: 0}
}
private currentPopupView: EventEmitter<any> = new EventEmitter<any>();
private dataModules: ModuleModel[] = this.getDataModules();
private dataMinMaxSum: {};
private dataCalculateVariationOrg: any[];
private dataChangeExecutor: any[];
subscribe(generatorOrNext?: any, error?: any, complete?: any) {
this.currentPopupView.subscribe(generatorOrNext, error, complete);
}
calculte(){
return this.priceService.getDataPrice();
}
getDataModules(){
this.httpService.getDataModules().subscribe(((modules)=>{this.dataModules = modules; console.log(this.dataModules);}));
console.log('dataModules');
console.log(this.dataModules);
return this.dataModules;
}
---------------------------------------------------------------------------
}
My left-block.component
import { Component, OnInit} from '#angular/core';
import { ModuleDataService } from '../../service/data-all.service';
import { ModuleModel } from '../../service/model-module';
#Component({
moduleId: module.id,
selector: 'modules-left-block',
templateUrl: './modules-left-block.html',
styleUrls: ['modules-left-block.css']
})
export class ModuleLeft implements OnInit{
modules: ModuleModel[];
constructor(private modulesAll: ModuleDataService){}
ngOnInit(){
this.modules = this.modulesAll.getDataModules();
console.log("view");
console.log(this.modulesAll.getDataModules());
}
onToggle(module: any){
this.modulesAll.toggleModules(module);
}
}
My left-block.component.html
<div class="modules-all">
<div class="modules-all-title">Все модули</div>
<div class="module-item" *ngFor="let module of modules" [ngClass]="{ 'active': module.completed }" (click)="onToggle(module)">{{module?.title}}</div>
</div>
In the component this.modulesAll.getDataModules () method is why it is executed only once without updating (write in console => undefined), if there are any thoughts, write, thanks.
This behaviour is due to the .subscribe() method does not wait for the data to arrive and I'm guessing you already know this. The problem you're facing is because, you have .subscribe to the getDataModules() service in the wron place. You shouldn't subscribe to a service in another service (at leat in this case). Move the subscribe method to the left-block.component and it should work.
getDataModules() {
this.httpService.getDataModules().subscribe(((modules) => {
this.dataModules = modules;
console.log(this.dataModules);
}));
console.log('dataModules');
console.log(this.dataModules);
return this.dataModules;
}
It should look somethig like this:
#Component({
moduleId: module.id,
selector: 'modules-left-block',
templateUrl: './modules-left-block.html',
styleUrls: ['modules-left-block.css']
})
export class ModuleLeft implements OnInit {
modules: ModuleModel[] = new ModuleModel();
constructor(private modulesAll: ModuleDataService, private httpService: HttpService) {}
ngOnInit() {
this.getDataModles();
//this.modules = this.modulesAll.getDataModules();
console.log("view");
//console.log(this.modulesAll.getDataModules());
}
onToggle(module: any) {
this.modulesAll.toggleModules(module);
}
getDataModules(): void {
this.httpService.getDataModules().subscribe(((modules) => {
this.modules = modules;
console.log(this.dataModules);
}));
}
}
So, What I am trying to do seems like it would be trivial. And it probably is. But I can't figure it out. My question is:How can I pass a variable from #Input to a service in an Angular2 component? (Code has been simplified)
My component is as follows:
import { Component, Input } from '#angular/core';
import { CMSService } from '../cms.service';
#Component({
selector: 'cmstext',
templateUrl: './cmstext.component.html',
styleUrls: ['./cmstext.component.css']
})
export class CMSTextComponent {
constructor(private cms: CMSService) { }
#Input() id : string;
content = this.cms.getContent(this.id); // this.id is NULL so content is NULL
}
And then my service:
import { Injectable } from '#angular/core';
#Injectable()
export class CMSService {
constructor() { }
getContent(textId:string) : string {
this.text = textId; // textId is NULL so this.text returns NULL
return this.text;
}
}
My component template:
<p>id: {{id}}</p>
<p>Content: {{content}}</p>
When <cmstext id="4"></cmstext> is added to another component template the output is:
id: 4
content:
I'm just diving into Angular2 any help or suggestions would be greatly appreciated!
Just make it a setter and put the code there:
#Input()
set id(value : string) {
this.content = this.cms.getContent(value);
}
As pointed out by #Kris Hollenbeck,ngOnInit() was the answer. My final code looked like this. The component now passed the variable to the service.
import { Component, Input, OnInit } from '#angular/core';
import { CMSService } from '../cms.service';
#Component({
selector: 'cmstext',
templateUrl: './cmstext.component.html',
styleUrls: ['./cmstext.component.css']
})
export class CMSTextComponent implements OnInit {
public content : string;
#Input() id : string;
constructor(private cms: CMSService) { }
ngOnInit() {
this.content = this.cms.getContent(this.id);
}
}
This assigned the data from the service to the variable "content" and the id passed from the element attribute to the variable "id". Both variables were then accessible to the template!
I am trying to pass a simple string object from a parent component to a sub-child component. I have tried doing it the following way:
parent.ts
import {Component} from 'angular2/core';
import {Router,ROUTER_DIRECTIVES,ROUTER_PROVIDERS,RouteConfig} from 'angular2/router';
import {ChildCmp} from "./child";
import {bootstrap} from 'angular2/platform/browser';
#Component({
selector: 'app',
template:`
<router-outlet></router-outlet>
`,
directives: [ROUTER_DIRECTIVES]
})
export class ParentCmp{
public data = "Some data from parent.";
constructor (private _router:Router){
var config = [];
if(!this._router.registry.hasRoute("Child",ParentCmp))
config.push({path: "/child/...",component:ChildCmp,name: 'Child',useAsDefault:true, data: {"data": this.data}});
this._router.config(config);
}
}
bootstrap(ParentCmp,[
ROUTER_PROVIDERS
]);
child.ts
import {Component} from 'angular2/core';
import {RouteData,Router,ROUTER_DIRECTIVES,RouteConfig} from 'angular2/router';
import {SubChildCmp} from "./sub_child";
#Component({
selector: 'child',
template: `<router-outlet></router-outlet>`,
directives: [ROUTER_DIRECTIVES]
})
#RouteConfig([
])
export class ChildCmp{
public data:Object;
constructor(private _data:RouteData,private _router:Router){
this.data = this._data.get("data");
var config = [];
if(!this._router.registry.hasRoute("SubChild",ChildCmp))
config.push({path:"/sub_child",component: SubChildCmp,name:"SubChild", useAsDefault:true, data:{"data":this.data}});
this._router.config(config);
}
}
sub_child.ts
import {Component} from 'angular2/core';
import {RouteData} from 'angular2/router';
#Component({
selector: "sub-child",
template: `Data from parent is -->
{{data}}
`
})
export class SubChildCmp{
public data:Object;
constructor(private _data:RouteData){
this.data = this._data.get("data");
}
}
But I am getting a blank page. It looks like the routing configuration in child.ts is not being configured properly. How can I achieve this? I just want to pass some data from parent component to sub-child component. I re-produced the problem here on plunker
Usually a service is used for this use case
#Injectable
export class SharedData {
data;
}
#Component({
selector: 'app',
providers: [SharedData],
template:`
<router-outlet></router-outlet>
`,
directives: [ROUTER_DIRECTIVES]
})
export class ParentCmp{
public data = "Some data from parent.";
constructor (private _router:Router, private _sharedData:SharedData){
var config = [];
if(!this._router.registry.hasRoute("Child",ParentCmp))
_sharedData.data = this.data;
}
}
}
export class SubChildCmp{
public data:Object;
constructor(_sharedData:SharedData){
this.data = _sharedData.data;
}
}
Using Observable or BehaviorSubject with subscribe() might be necessary if there are timing issues, for example when SubChildCmp reads the value before the ParentCmp has set it.
For more details see https://angular.io/docs/ts/latest/cookbook/component-communication.html#!#bidirectional-service