Bind ngModel value across components - angularjs

Say you have about.component.ts with the following:
import { Component } from '#angular/core';
#Component({
selector: 'about-section',
template: `
<input [(ngModel)]="name" placeholder="First Name">
<p>{{name || 'user'}}</p>
`
})
export class AboutComponent {
}
Then you have notes.component.ts:
import { Component } from '#angular/core';
#Component({
selector: 'notes-section',
template: `
<p>{{name || 'user'}}</p>
`
})
export class NotesComponent {
}
Both files are components of app.component.ts:
import { Component } from '#angular/core';
import { AboutComponent } from './about.component';
import { NotesComponent } from './notes.component';
#Component({
selector: 'my-app',
template: `
<about-section></about-section>
<notes-section></notes-section>
`,
directives: [AboutComponent, NotesComponent]
})
export class AppComponent { }
My question is, how would you bind the ngModel 'name' property from about.component.ts to notes.component.ts so whenever you write your name, the change is reflected both in the notes component and the about component?

One way to do it is using EventEmitter:
#Component({
selector: 'about-section',
template: `
<input [ngModel]="name" (ngModelChange)="name = $event; modelChanged.emit($event)">
<p>{{name || 'user'}}</p>
`
})
export class AboutComponent {
#Output() modelChanged = new EventEmitter();
}
#Component({
selector: 'notes-section',
template: `<p>{{name || 'user'}}</p>`
})
export class NotesComponent {}
#Component({
selector: 'my-app',
template: `
<about-section (modelChanged)="notes.name = $event"></about-section>
<notes-section #notes></notes-section>`,
directives: [AboutComponent, NotesComponent]
})
export class AppComponent { }
Check demo plunker here
Firstly i extracted banana in a box [(ngModel)]="name" (https://angular.io/docs/ts/latest/guide/template-syntax.html#!#two-way-binding-with-ngmodel) to emit EventEmitter event from the component containing ngModel.
<input [ngModel]="name" (ngModelChange)="name = $event; modelChanged.emit($event)">
Then i just subscribed to this event in parent component:
<about-section (modelChanged)="notes.name = $event"></about-section>
but before it i kept reference on other component to be able to change name as shown in the above code notes.name = $event where $event is representing "payload" of the raised event (input value in this case).
<notes-section #notes></notes-section>

Related

How to access DOM element in other component in Angular 6?

I have two components header & a. In header component there is a hidden element and I want to show it from component a, but I don't know how do I do this.
header.component.html
<p>
header works!
</p>
<div #hidden_element style="display: none">
<h1>Hidden Element in header</h1>
</div>
a.component.html
<div (click)="show()">Show</div>
a.component.ts
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-a',
templateUrl: './a.component.html',
styleUrls: ['./a.component.css']
})
export class AComponent implements OnInit {
constructor() { }
show() {
// code to display hidden element in header component
}
ngOnInit() {
}
}
app.component.html
<app-header></app-header>
<app-a></app-a>
You can do it by sending events between directives via a custom service. A simple example would look something like this:
// my-service.component.ts
import { Injectable } from "#angular/core";
import { Subject } from "rxjs/index";
#Injectable()
export default class MyService {
private messageSource = new Subject<string>();
listener = this.messageSource.asObservable();
send(message: string): void {
this.messageSource.next(message);
}
}
Your 'a' component will look something like this:
// a.component.ts
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-a',
templateUrl: './a.component.html',
styleUrls: ['./a.component.css']
})
export class AComponent implements OnInit {
constructor(private myService: MyService) { }
show() {
// code to display hidden element in header component
this.myService.send('some message');
}
ngOnInit() {
}
}
and this is your header component:
// header.component.ts
#Component({
selector: 'app-header',
templateUrl: './header.component.html',
styleUrls: []
})
export class HeaderComponent implements OnDestroy {
private serviceSubscription: Subscription;
constructor(private myService: MyService) {
this.serviceSubscription = this.myService.listener.subscribe(message => {
// TODO: Do whatever you want to do here to show the hidden element
});
}
ngOnDestroy(): void {
this.serviceSubscription.unsubscribe();
}
}

Call angular method in series -Highcharts

All I'm a newbie in learning Angular and highchairs. My issue is how to call angular method in series to render charts dynamically.
I referred this link ,but i'm not understanding anything from that:
link:https://www.highcharts.com/blog/tutorials/194-using-highcharts-with-angular-js/.
link: Call an angular component method when we click on highchart series
Kindly app me to solve this.
app.component.ts
import { Component } from '#angular/core';
import { HttpClient } from '#angular/common/http';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
name:string = '';
age:number;
found:boolean;
constructor(private httpClient: HttpClient) { }
onNameKeyUp(event:any){
this.name = event.target.value;
this.found = false;
}
getProfile(){
this.httpClient.get(`https://my-json-server.typicode.com/techsithgit/json-faker-directory/profiles/?name=${this.name}`)
.subscribe(
(data:any[] )=>{
if(data.length){
this.age = data[0].age;
this.found = true;
}
}
)
}
}
app.component.html
<input type ="text" (keyup) = "onNameKeyUp($event)">
<button (click)= "getProfile()">Get User Details</button>
<br>
<div *ngIf="found" >
<span>{{name}}'s age is {{age}}</span>
</div>

Dynamic *ngIf template

Would like to show dynamic data using *ngIf and ng-template. For example I would to display the title 'List of courses' if courses.length > 0 or No courses yet when courses.length == 0
So far, I have my
courses.component.html
<div *ngIf="courses.length > 0; then coursesList else noCourses">
<ng-template #coursesList>
List of courses
</ng-template>
<ng-template #noCourses>
No courses yet
</ng-template>
</div>
my app.component.html
<app-ng-if-courses [courses]="courses"></app-ng-if-courses>
my ng-if-courses.component.ts
import { Component, OnInit, Input } from '#angular/core';
#Component({
selector: 'app-ng-if-courses',
templateUrl: './ng-if-courses.component.html',
styleUrls: ['./ng-if-courses.component.css']
})
export class NgIfCoursesComponent implements OnInit {
#Input('courses') courses = [];
constructor() { }
ngOnInit() {
}
}
my app.component.ts
import { } from './ng-if-courses/ng-if-courses.component';
import { Component } from '#angular/core';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'Angular app';
// <app-ng-if-courses>
// courses = [];//no courses
courses = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15];
}
I think it will be very simple but I am a learning AngularJS

Angular 2 Communicating with <router-outlet> components

I have a search bar in a header component.
Beneath that, I have a "router-outlet" in that same component.
The search bar (input txtfield), once enter is pressed, needs to send the search string (event.target.value) to the component that resides within the router-outlet beneath it so that it can run a method to return the results.
I have no clue what the best way is to achieve this.
UPDATED with code..
app.component.html:
<div class="white-container">
<input name="searchStr" [(ngModel)]="searchStr" (keyup.enter)="searchCourse($event)">
</div>
<router-outlet></router-outlet>
app.component.ts:
import { Component, OnInit } from '#angular/core';
import { CourseService } from './services/courses.service';
import { Course } from './Course';
#Component({
selector: 'my-app',
templateUrl: 'app.component.html',
providers: [CourseService]
})
export class AppComponent implements OnInit {
constructor(private _courseService: CourseService) {
}
searchCourse(event) {
// the user search string here...
}
}
/course-listings/course-listings.component.ts:
import { Component, OnInit } from '#angular/core';
import { CourseService } from './services/courses.service';
import { Course } from './Course';
#Component({
selector: 'app-course-listings',
templateUrl: './course-listings.component.html',
styleUrls: ['./course-listings.component.css'],
providers: [CourseService]
})
export class AppComponent implements OnInit {
course: Course[];
constructor(private _courseService: CourseService) {
}
searchCourse(evt) {
// This works once it's fired...
this._courseService.findCourse(evt)
.subscribe(courses => {
this.course = courses;
});
}
}
/services/courses.service.ts:
import {Injectable} from '#angular/core';
import {Http} from '#angular/http';
import 'rxjs/add/operator/map';
#Injectable()
export class CourseService {
constructor(private _http:Http) {
}
getCourses(search) {
return this._http.get('/api/v1/courses/'+search)
.map(res => res.json());
}
}
FIX FOUND
Günter Zöchbauer was correct. I used a service w/ subscribe and observables to do it. Thanks.
An event.subscriber would be required in the constructor to pass to router-outlet.
Similar to the answer in this Angular 2 router event listener.
So, once the click is done, the subscriber event will be executed based on on the navigationend event, then the value can be accessed.

Angular 2 I don't know how to delete a row of a pushed Object

First let me be clear about my problem/issue:
First it was like this: https://www.dropbox.com/s/92z2oe7f4w5x2b5/conditions.jpg?dl=0 Here it deletes the last created Object in my case Conditions.
but i want to delete each condition separately like this see the red box next to each row: https://www.dropbox.com/s/ptwq6sk6da4p21k/new.jpg?dl=0
import {Component, OnInit, DynamicComponentLoader, Input} from 'angular2/core';
import {Condition} from './condition';
import {DateCondition} from './datecondition.component';
import {StringCondition} from './stringcondition.component';
import {SelectCondition} from './selectcondition.component';
import {ConditionDetailComponent} from './conditiondetail.component';
import {ConditionService} from './condition.service'
#Component({
selector: 'condition-builder',
templateUrl: 'app/conditionbuilder.component.html',
directives: [ConditionDetailComponent],
})
export class ConditionBuilderComponent implements OnInit {
conditions: Condition[] = [];
catalog: Condition[] = [];
constructor(public _conditionService: ConditionService) { }
getConditions() {
this._conditionService.getConditions().then(conditions => this.catalog = conditions);
}
ngOnInit() {
this.getConditions();
}
onChange(conditionsIndex, selectedCondition:string): void {
this.conditions[conditionsIndex] = this.catalog.find(condition => condition.name == selectedCondition);
}
newCondition() {
this.conditions.push(this.catalog[0]);
}
deleteCondition() {
this.conditions.pop();
}
}
In the code above i'll import the getConditions with the object of conditions in my case. Does any one know how i do this and what is the best way to handle this issue?
Here i want to
import {Component, OnInit, Input, DynamicComponentLoader, ElementRef} from 'angular2/core';
import {Condition} from './condition';
import {DateCondition} from './datecondition.component';
import {StringCondition} from './stringcondition.component';
import {SelectCondition} from './selectcondition.component';
import {ConditionBuilderComponent} from "./conditionbuilder.component";
#Component({
selector: 'condition-detail',
template: '<div #child></div>'
+ '<a class="btn btn-danger" (click)="deleteCondition()"><i class="glyphicon glyphicon-minus"></i></a>'
})
export class ConditionDetailComponent implements OnInit {
#Input() condition: Condition;
dcl:DynamicComponentLoader;
elementRef:ElementRef;
constructor(dcl: DynamicComponentLoader, elementRef: ElementRef) {
this.dcl = dcl;
this.elementRef = elementRef;
}
ngOnInit() {
this.dcl.loadIntoLocation(this.condition, this.elementRef, 'child');
}
deleteCondition() {
HOW CAN I DELETE THE CONDITION ROW HERE?
}
Like this is the code build, ill hope it is clear for you to help me out. How does the deleteCondition method know which row he needs to deleten and how do i delete it out of the array in the code above the page?
Ill hope someone can help me out!!
You could provide the list to the sub component and remove the current element from it. This way the associated component in the loop will be removed.
The main component:
#Component({
selector: 'my-app',
template: `
<div *ngFor="#elt of data">
<my-component [elt]="elt" [data]="data"></my-component>
</div>
`,
directives: [MyComponent]
})
export class AppComponent {
constructor() {
this.data = [
{name: 'name1'},
{name: 'name2'},
{name: 'name3'},
{name: 'name4'}
];
}
}
The child component:
#Component({
selector: 'my-component',
template: `
<div>{{elt.name}} <span (click)="delete()">X</span></div>
`
})
export class MyComponent {
#Input()
elt: any;
#Input()
data: any[];
delete() {
var index = this.data.indexOf(this.elt);
this.data.splice(index, 1);
}
}
See this plunkr: https://plnkr.co/edit/o5O0Rr?p=preview.

Resources