Using Angular Service to provide data into different component - html

My intention is to send data from one component to another. The user can choose between 3 different offers - the click events provide different data (in this case numbers from 1 to 3) - these data is saved in the Sender as "selectedDiv" - (following isn't working) data from "selectedDiv" shall be send to Reciever and is also to be updated when "selectedDiv" in the sending component changes.
I've already found suggestions on stackoverflow.com, but none of them worked out for me.
Summarized:
The component which is supposed to send data contains a number which is to be forwarded to a different component.
My progress so far:
Service:
export class SelectedService {
selectedDiv: number;
changeNumber(div: number) {
this.selectedDiv = div;
}
}
Sender:
import { Component, OnInit } from '#angular/core';
import {SelectedService} from '../selected.service';
#Component({
selector: 'app-wedding',
templateUrl: './wedding.component.html',
styleUrls: ['./wedding.component.css'],
providers: [SelectedService]
})
export class WeddingComponent implements OnInit {
selectedDiv: number;
public onChoose(event): void {
this.selectedDiv = event;
this.selectedService.changeNumber(this.selectedDiv);
}
constructor(private selectedService: SelectedService) {
}
ngOnInit() {
}
}
Reciever:
import { Component, OnInit } from '#angular/core';
import {SelectedService} from '../selected.service';
#Component({
selector: 'app-contact',
templateUrl: './contact.component.html',
styleUrls: ['./contact.component.css'],
providers: [SelectedService]
})
export class ContactComponent implements OnInit {
selectedDiv: number;
constructor(private selectedService: SelectedService) {
this.selectedDiv = this.selectedService.selectedDiv;
}
ngOnInit() {
}
}
Edit:
The first approach showed following error: this.selectedService.changeNumber is not a function
Screenshot from Augury (receiving component somehow remains empty):
Sending WeddingComponent:
WeddingComponent
Receiving ContactComponent:
ContactComponent

The issue is that you are providing the SelectedService directly in the components, therefore you are getting two different instances of the same class.
You have 3 solutions:
Register the provider in a component parent of both WeddingComponent and ContactComponent
Register the provider in the module containing both WeddingComponent and ContactComponent
Add provideIn: root as a parameter of the Injectable decorator directly in the service
Depending on the scope of the service you need to choose one option.

Related

How to call a component from other component in angular 7

I have a checkbox,if that checkbox is checked, I need to show alert message on load the application.But problem is that checkbox is in header component and it is linked with home component.So when I will be in home page and if that checkbox is checked, I need to show alert message on load the application. Here is the code below,
header.component.html
<div><input checked type="checkbox">Other-component</div>
header.component.ts
import { Component, OnInit } from '#angular/core';
import { Router } from "#angular/router";
#Component({
selector: 'app-header',
templateUrl: './header.component.html',
styleUrls: ['./header.component.css']
})
export class HeaderComponent implements OnInit {
constructor(public router: Router){}
ngOnInit() {}
}
home.component.ts
import { Component, OnInit } from '#angular/core';
import { FormBuilder, FormGroup, Validators } from '#angular/forms';
import Speech from 'speak-tts';
import { RxSpeechRecognitionService, resultList, } from '#kamiazya/ngx-speech-recognition';
#Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.css'],
providers: [ RxSpeechRecognitionService ]
})
export class HomeComponent implements OnInit {
showit:any;
nestedjson:any;
constructor(private formBuilder: FormBuilder,public service: RxSpeechRecognitionService) {
}
ngOnInit() {
}
}
1) To the question in your headline: How to call a component from other component
You can give the header component a reference id inside the home template.
<app-header #header></app-header>
Then you can access the header component through a ViewChild in your home component.
#ViewChild('header') headerComponent: HeaderComponent;
But this does not seem to be very good practice for your needs. Consider using a service and subscribe to a Subject by using RxJs Observables. Or much simpler in your case: just use two-way-data-binding.
2) The way you should actually communicate between components: two way data binding
header.component.ts
export class HeaderComponent implements OnInit {
#Input() isChecked: boolean;
#Output() isCheckedChanged = new EventEmitter<boolean>();
constructor(public router: Router){}
ngOnInit() {
}
}
header.component.html
<input [(ngModel)]="isChecked" type="checkbox">
home.component.ts
export class HomeComponent implements OnInit {
isChecked: boolean;
constructor() {}
ngOnInit() {
}
}
home.component.html
<app-header [(isChecked)]="isChecked"></app-header>
Edit: in your case you also don't need two way binding since you don't need any feedback from the HeaderComponent. One way data binding will be fine. Then you can remove the line
#Output() isCheckedChanged = new EventEmitter<boolean>();
And in Home template don't use banana in the box syntax [()], instead just use []:
<app-header [isChecked]="isChecked"></app-header>
You can make use of a service which is defined at the root level.And then with the help of a service you can either emit or use Subjects to capture in your home component.

Component Interaction #Input

I would like a component to send input to another component. Below is the code .ts and .html. of the two components.
Now the problem is that the html page of the parent component also shows the html part of the child component ... I want the component to pass only one string to the child component
Parent.ts
import ...
#Component({
selector: 'app-parent',
templateUrl: './parent.html',
styleUrls: ['./parent.css']
})
export class ParentComponent implements OnInit {
sostegno : string;
constructor() { }
ngOnInit() { }
avvia1() {
this.sostegno = "xxx";
this.router.navigate(['./xxx'], { relativeTo: this.route });
}
avvia2()
this.sostegno = "yyy";
this.router.navigate(['./yyy'], { relativeTo: this.route });
}
}
Parent.html
<div>
...
</div>
<app-child [sostegno]="sostegno"></app-child>
Child.ts
import ...
#Component({
selector: 'app-child',
templateUrl: './child.html',
styleUrls: ['./child.css']
})
export class ChildComponent implements OnInit {
#Input() sostegno : string;
constructor() { }
ngOnInit() {
console.log(this.sostegno);
}
}
There are some changes which you need to make because looking at the code which your currently have it seems incomplete.
You are using this.router without injecting the Router class in your constructor.
You are using this.route without injecting the ActivatedRoute class in your constructor.
To test that your parent > child interaction is working you can remove your param and instead place a test for the html
<app-child [sostegno]="'Test'"></app-child>
This should work for your ngOnInit function which is inside of your child component. If this works all you need to do now is either initialize sostegno in your parent component else your console log inside your child component will not reflect the changes when you call avvia1 or avvia2 inside of your parent class.
Hope this helps!

JSON service returning undefined property with Angular 7

This should be the simplest thing. I have a component that calls a service that imports a local JSON directly (see Import JSON directly with Angular 7)
It reads the JSON contents fine, but the pages property is undefined. I think I set everything up based on the StackBlitz in that link, there doesn't seem to be much to it. There isn't any HTML yet, this is all just via the console. It's in app.component.html.
Reading local json files json.service.ts:14
[{…}]0: {name: "Home"}length: 1__proto__: Array(0) json.service.ts:15
undefined home.component.ts:31
json.service.ts:
import { Injectable } from '#angular/core';
import SampleJson from '../assets/SampleJson.json';
export interface JsonInterface {
name: any;
}
#Injectable()
export class JsonService {
ngOnInit() {
console.log('Reading local json files');
console.log(SampleJson);
}
}
home.component.ts:
import { JsonService, JsonInterface } from '../json.service';
import { Component, OnInit, Input } from '#angular/core';
#Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.scss']
})
export class HomeComponent implements OnInit {
constructor(service: JsonService) {
service.ngOnInit();
};
#Input() pages: JsonInterface;
ngOnInit() {
console.log(this.pages);
}
}
Sample.json
{ "name":"Home" }
If I understand your log correctly, it works as expected:
constructor(service: JsonService) {
service.ngOnInit();
};
You request the service and you get an instance. Then you call ngOnInit:
ngOnInit() {
console.log('Reading local json files');
console.log(SampleJson);
}
Now it logs the "reading…" and the content of your json file.
ngOnInit() {
console.log(this.pages);
}
Then you log this.pages which is empty. You never filled it. You never did anything with your service or the data loaded in your service.
I think what you want is something like this
export class JsonService {
getPages() { return SampleJson; }
}
and in your component:
constructor(private service: JsonService) {}
ngOnInit() {
this.pages = this.service.getPages();
console.log(this.pages);
}
The sample code is not tested but I think you've got the point.
The problem is with pages. You have inly declared 'pages' as 'JsonInterface' which is only the type of 'pages' but never initialized with any value so it is undefined.. you need to write a function in Service as the above answer by #Christoph .
I hope you understand why this error occured and If you are not inputting a value to 'pages' from html you don't need to declare it as '#Input'.

Open modal form containing form created from ngx-formly from another ngx-formly form

I'm currently using ngx-formly to dynamically create a bunch of Angular forms from JSON, which works really nicely. I have a peculiar use case where a custom button on a form, should open a modal dialog containing another form on click, which would also contain a form created using ngx-formly. The example I saw on the ngx-formly site use a custom button, and creates a custom component with .ts files, but I want to avoid that since I would have several forms doing this, and I don't want to create different components for this.
Is there a way to trigger a modal dialog from an ngx-formly form, to show the modal with ngx-formly form without having to create multiple components(.ts) files for them?
Common Bootstrap Model with dynamic data
Example with jQuery:
https://stackblitz.com/edit/ngx-bootstrap-fh92s3
modal.service.ts
import {Injectable} from '#angular/core';
import {ModalModel} from './modal.model';
import {Subject} from "rxjs/Subject";
declare let $: any;
#Injectable()
export class ModalService {
modalData = new Subject<ModalModel>();
modalDataEvent = this.modalData.asObservable();
open(modalData: ModalModel) {
this.modalData.next(modalData);
$('#myModal').modal('show');
}
}
modal.component.ts
import { Component } from '#angular/core';
import { ModalService } from './modal.service';
import {ModalModel} from './modal.model';
declare let $: any;
#Component({
selector: 'app-modal',
templateUrl: './modal.component.html',
styleUrls: [ './modal.component.css' ]
})
export class ModalComponent {
modalData: ModalModel;
constructor(private modalService: ModalService) {
this.modalService.modalDataEvent.subscribe((data) => {
this.modalData = data;
})
}
}
calling this service from any component
import { Component } from '#angular/core';
import { ModalService } from '../modal/modal.service';
import { ModalModel } from '../modal/modal.model';
declare let $: any;
#Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: [ './home.component.css' ]
})
export class HomeComponent {
modelData = new ModalModel();
constructor(private modalService: ModalService) {
}
open() {
this.modelData.header = 'This is my dynamic HEADER from Home component';
this.modelData.body = 'This is my dynamic BODY from Home component';
this.modelData.footer = 'This is my dynamic footer from Home component';
this.modalService.open(this.modelData);
}
}
Example without jQuery i.e with ngx-bootstrap: https://stackblitz.com/edit/angular-ngx-bootstrap-modal

How can i get a variable from different TS page in HTML?

i'm working on ionic2 and i have two HTML pages (page1.html and page2.html)
how can i get a variable from page1.ts and show it in page2.html ?
If you used ionic g page to create your page1.html and page2.html file, then you should have .ts file associated with every html. You can store variables in that typescript file. And pass those variables between pages using Ionic's NavParams.
https://ionicframework.com/docs/api/navigation/NavParams/
Use a provider for that. Following code to share user's name-
global.provider.ts
import { Injectable } from '#angular/core';
#Injectable()
export class GlobalProvider {
public userName: any;
setUserName(name: string) {
this.userName= name;
}
}
Page1.ts
import { GlobalProvider } from '../providers/global.provider';
#Component({
templateUrl: 'page1.html'
})
export class Page1Page{
constructor(private _globalProvider : GlobalProvider) {}
this.globalProvider.setUserName('John');
}
Page2.ts
import { GlobalProvider } from '../providers/global.provider';
#Component({
templateUrl: 'page2.html'
})
export class Page2Page{
public user: any;
constructor(private _globalProvider : GlobalProvider) {}
this.user = this._globalProvider.userName;
console.log(this.user); // John
}