Why does #output event produce error "TypeError: _co.XXXXX is not a function' - angular-components

Writing an Angular child component, and can't convince the parent to capture a value emitted through #Output. It throws an error that the receiver _co.pinEvent is undefined. During initialization, though, the debugger shows it successfully making the call. So it's not a simple typo.
Followed every guide and question I could find, cut it down to minimal example, and still can't get it to work. The component reference _co seems to be pointing at something other than the home component.
home.module.ts
...
import { KeypadComponent } from '../keypad/keypad.component';
#NgModule({
...
declarations: [HomePage, KeypadComponent]
})
export class HomePageModule {
digits: number;
title: string;
change: any;
constructor() {
}
pinEvent($event) {
console.log(JSON.stringify($event));
}
}
home.page.html
<ion-content>
<ble-lock-keypad (pinValue)="pinEvent($event)"></ble-lock-keypad>
Once the component is visible, any event emitted
from child causes this pinEvent() call to fail on
an undefined reference.
</ion-content>
keypad.component.ts
#Component({
selector: 'ble-lock-keypad',
templateUrl: './keypad.component.html'
})
export class KeypadComponent {
#Output() pinValue: EventEmitter<string> = new EventEmitter<string>();
constructor() {
}
handleInput(key: string) {
this.pinValue.emit(key);
}
}
keypad.component.html
<ion-button (click)="handleInput('1')">1</ion-button>
Getting really tired of seeing this error:
TypeError: _co.pinEvent is not a function. (In '_co.pinEvent($event)', '_co.pinEvent' is undefined)
Can anyone point out what's going wrong?

Related

angular 11 display static text to dynamic value

I'm having 2 JSONs. The first one is having the format of the JSON value and the second one is having the actual value which is I want to display in the UI.
But I'm seeing the "application.appID" instead of 101. Does any help please?
Not working if label:"applicaiton.appID". I'm having label: "string"
working if label: applicaiton.appID
component.ts
this.json1={
label:"applicaiton.appID"
};
this.application ={
appID:101
};
ui.html
<mat-label> {{json1.label}} </mat-label>
<mat-label [innterHtml]="json1.lable"> </mat-label>
If I understand right, what you're trying to do is to interpolate based on a string expression coming from a json. This is not something that you can do by just using the {{ }} construct. Here's why:
(For simplicity I will use div instead of mat-label)
In theory, this line would solve your problem
<div>{{this[json1.label]}}</div>
Just that it doesn't work since the inner json1.label part is not expanded/evaluated as expected.
Even if we manually write it as an explicit string, it still doesn't give us 101.
<div>{{this['application.appID']}}</div>
The only way to make such a syntax work would be to chain the field indexers, but that doesn't help us with using json1.label as the 'path' of the object and inner field.
<div>{{this['application']['appID']}}</div> // this returns 101, but it's not helpful for us...
So as you can see, pure html interpolation can't really help us achieve our goal. Instead, we should create a helper method inside the .component.ts file:
import { Component } from '#angular/core';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent {
json1 = {
label: 'application.appID'
};
application = {
appID: 101
};
accessPropertyByString(path: string): any {
let result = this;
const parts = path.split('.');
for (const part of parts) {
if (part in result) {
result = result[part];
} else {
return null;
}
}
return result;
}
}
The new accessPropertyByString() method can be now used in the html template like this:
<div>{{accessPropertyByString(json1.label)}}</div>
Which finally returns 101 as expected.

React Native: Yet another "Undefined is not an object (evaluating action.type)

I'm developing a CRNA application, however, the store connection is not working and I'm receiving the above error when creating the store.
"Undefined is not an object (evaluating action.type)
Searching for similar problems, I got to this question, which is a reducer being called while passed to the createStore function, which is not my case.
And this one, which is related to AnalyticsTracker called before an async dispatcher, also not my case.
Here's the minimum code to reproduce.
App.js
import React from 'react';
import {
View,
Text
} from 'react-native';
import { Provider } from 'react-redux';
import store from './store';
class App extends React.Component {
render() {
return (
<Provider store={store}>
<View>
<Text>Hello</Text>
</View>
</Provider>
);
}
}
store.js
import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import reducer from './reducer';
// Here the error happens
export default createStore(reducer, applyMiddleware(thunk));
reducer.js
import actionTypes from './action_types';
const initialState = {
}
export default (action, state=initialState) => {
// This is the top line on stacktrace
switch (action.type) {
case actionTypes.MY_ACTION:
return state;
}
return state;
}
I have tried a few changes in my code, i.e: removing the middlewares.
Any idea why is it happening? Am I missing something?
I have noticed that your createStore call is false, since enhancers are passed as the third parameter. Change it to:
const store = createStore(persistedReducer, undefined, applyMiddleware(thunk));
Additionally the structure of your reducer is false. Your first parameter in your reducer should be the initialState followed by the action as the second parameter - this is why you get undefined is not an object!.
As described in Reducers, it has to have a signature of (previousState, action) => newState, is known as a reducer function, and must be pure and predictable.
From: https://redux.js.org/recipes/structuringreducers

Angular ActionCable call method in component when notification received

I'm trying to practice using ActionCable in Angular. I created a quick Rails application that I put up on Heroku and then created an Angular application with the actioncable npm module as a dependency.
I configured my Rails appplication to allow http://localhost:4200 as an origin while I play around with my Angular app in development. I also didn't make this an API application because I wanted to have a working UI from the get-go. So I can log into the Rails application, send a message, and my separate Angular application is subscribed to that channel as well. I'm successfully receiving those notifications/messages.
Now I'd like to render something in Angular based on that message. I think I'm missing something pretty silly here, but I cannot refer to methods in the component that instantiates the subscription to that channel in the receive callback of the subscription.
import {
ComponentFactoryResolver,
ComponentRef,
OnInit,
ViewContainerRef,
Component,
ViewChild,
Output
} from '#angular/core';
import * as ActionCable from 'actioncable';
import { MessageComponent } from 'app/message/message.component';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
messageRef: ComponentRef<MessageComponent>;
#ViewChild('message', { read: ViewContainerRef }) message: ViewContainerRef;
title = 'app works!';
private cable: ActionCable.Cable;
private subscription: ActionCable.Channel;
constructor(
private componentFactoryResolver: ComponentFactoryResolver,
private viewContainerRef: ViewContainerRef) {
}
public ngOnInit(): void {
this.cable = ActionCable.createConsumer('wss://<my-heroku-app>.herokuapp.com/cable');
this.subscription = this.cable.subscriptions.create(
'RoomChannel',
{
connected: this.connected,
disconnected: this.disconnected,
received: this.received,
});
}
private showMessage(messageString) {
if (!this.messageRef) {
const messageComponent = this.componentFactoryResolver.resolveComponentFactory(MessageComponent);
this.messageRef = this.message.createComponent(messageComponent);
}
this.messageRef.instance.message = messageString;
this.messageRef.changeDetectorRef.detectChanges();
}
private connected() {
console.log('connected!');
}
private disconnected() {
console.log('disconnected!');
}
private received(data: any) {
console.log('received');
// What do I put here? `this` is of type Subscription,
// and thus, I can't call `this.showMessage(data.message)`
}
}
I want to use some sort of predicate or inject something into that context (sorry if I'm not using the right terminology), but I am just not sure how to do this. I plan on cleaning things up instead of having this all in the AppComponent class, but for now I'm just trying to learn.
Any ideas? Thanks!
The answer seems to be this:
this.cable = ActionCable.createConsumer(this.url)
this.subscription = this.cable.subscriptions.create(
'RoomChannel',
{
connected: this.connected,
disconnected: this.disconnected,
// The key here, apparently, is to use a fat-arrow
// function so that the `this` I care about is
// lexicographically scoped. I still need to better
// understand what exactly that means, but I have a
// general idea.
received: (data) => this.received(data)
});

Angular 2 : How to watch service variables? [duplicate]

I am trying to implement something like a delegation pattern in Angular.
When the user clicks on a nav-item, I would like to call a function which then emits an event which should in turn be handled by some other component listening for the event.
Here is the scenario: I have a Navigation component:
import {Component, Output, EventEmitter} from 'angular2/core';
#Component({
// other properties left out for brevity
events : ['navchange'],
template:`
<div class="nav-item" (click)="selectedNavItem(1)"></div>
`
})
export class Navigation {
#Output() navchange: EventEmitter<number> = new EventEmitter();
selectedNavItem(item: number) {
console.log('selected nav item ' + item);
this.navchange.emit(item)
}
}
Here is the observing component:
export class ObservingComponent {
// How do I observe the event ?
// <----------Observe/Register Event ?-------->
public selectedNavItem(item: number) {
console.log('item index changed!');
}
}
The key question is, how do I make the observing component observe the event in question ?
Update 2016-06-27: instead of using Observables, use either
a BehaviorSubject, as recommended by #Abdulrahman in a comment, or
a ReplaySubject, as recommended by #Jason Goemaat in a comment
A Subject is both an Observable (so we can subscribe() to it) and an Observer (so we can call next() on it to emit a new value). We exploit this feature. A Subject allows values to be multicast to many Observers. We don't exploit this feature (we only have one Observer).
BehaviorSubject is a variant of Subject. It has the notion of "the current value". We exploit this: whenever we create an ObservingComponent, it gets the current navigation item value from the BehaviorSubject automatically.
The code below and the plunker use BehaviorSubject.
ReplaySubject is another variant of Subject. If you want to wait until a value is actually produced, use ReplaySubject(1). Whereas a BehaviorSubject requires an initial value (which will be provided immediately), ReplaySubject does not. ReplaySubject will always provide the most recent value, but since it does not have a required initial value, the service can do some async operation before returning it's first value. It will still fire immediately on subsequent calls with the most recent value. If you just want one value, use first() on the subscription. You do not have to unsubscribe if you use first().
import {Injectable} from '#angular/core'
import {BehaviorSubject} from 'rxjs/BehaviorSubject';
#Injectable()
export class NavService {
// Observable navItem source
private _navItemSource = new BehaviorSubject<number>(0);
// Observable navItem stream
navItem$ = this._navItemSource.asObservable();
// service command
changeNav(number) {
this._navItemSource.next(number);
}
}
import {Component} from '#angular/core';
import {NavService} from './nav.service';
import {Subscription} from 'rxjs/Subscription';
#Component({
selector: 'obs-comp',
template: `obs component, item: {{item}}`
})
export class ObservingComponent {
item: number;
subscription:Subscription;
constructor(private _navService:NavService) {}
ngOnInit() {
this.subscription = this._navService.navItem$
.subscribe(item => this.item = item)
}
ngOnDestroy() {
// prevent memory leak when component is destroyed
this.subscription.unsubscribe();
}
}
#Component({
selector: 'my-nav',
template:`
<div class="nav-item" (click)="selectedNavItem(1)">nav 1 (click me)</div>
<div class="nav-item" (click)="selectedNavItem(2)">nav 2 (click me)</div>`
})
export class Navigation {
item = 1;
constructor(private _navService:NavService) {}
selectedNavItem(item: number) {
console.log('selected nav item ' + item);
this._navService.changeNav(item);
}
}
Plunker
Original answer that uses an Observable: (it requires more code and logic than using a BehaviorSubject, so I don't recommend it, but it may be instructive)
So, here's an implementation that uses an Observable instead of an EventEmitter. Unlike my EventEmitter implementation, this implementation also stores the currently selected navItem in the service, so that when an observing component is created, it can retrieve the current value via API call navItem(), and then be notified of changes via the navChange$ Observable.
import {Observable} from 'rxjs/Observable';
import 'rxjs/add/operator/share';
import {Observer} from 'rxjs/Observer';
export class NavService {
private _navItem = 0;
navChange$: Observable<number>;
private _observer: Observer;
constructor() {
this.navChange$ = new Observable(observer =>
this._observer = observer).share();
// share() allows multiple subscribers
}
changeNav(number) {
this._navItem = number;
this._observer.next(number);
}
navItem() {
return this._navItem;
}
}
#Component({
selector: 'obs-comp',
template: `obs component, item: {{item}}`
})
export class ObservingComponent {
item: number;
subscription: any;
constructor(private _navService:NavService) {}
ngOnInit() {
this.item = this._navService.navItem();
this.subscription = this._navService.navChange$.subscribe(
item => this.selectedNavItem(item));
}
selectedNavItem(item: number) {
this.item = item;
}
ngOnDestroy() {
this.subscription.unsubscribe();
}
}
#Component({
selector: 'my-nav',
template:`
<div class="nav-item" (click)="selectedNavItem(1)">nav 1 (click me)</div>
<div class="nav-item" (click)="selectedNavItem(2)">nav 2 (click me)</div>
`,
})
export class Navigation {
item:number;
constructor(private _navService:NavService) {}
selectedNavItem(item: number) {
console.log('selected nav item ' + item);
this._navService.changeNav(item);
}
}
Plunker
See also the Component Interaction Cookbook example, which uses a Subject in addition to observables. Although the example is "parent and children communication," the same technique is applicable for unrelated components.
Breaking news: I've added another answer that uses an Observable rather than an EventEmitter. I recommend that answer over this one. And actually, using an EventEmitter in a service is bad practice.
Original answer: (don't do this)
Put the EventEmitter into a service, which allows the ObservingComponent to directly subscribe (and unsubscribe) to the event:
import {EventEmitter} from 'angular2/core';
export class NavService {
navchange: EventEmitter<number> = new EventEmitter();
constructor() {}
emit(number) {
this.navchange.emit(number);
}
subscribe(component, callback) {
// set 'this' to component when callback is called
return this.navchange.subscribe(data => call.callback(component, data));
}
}
#Component({
selector: 'obs-comp',
template: 'obs component, index: {{index}}'
})
export class ObservingComponent {
item: number;
subscription: any;
constructor(private navService:NavService) {
this.subscription = this.navService.subscribe(this, this.selectedNavItem);
}
selectedNavItem(item: number) {
console.log('item index changed!', item);
this.item = item;
}
ngOnDestroy() {
this.subscription.unsubscribe();
}
}
#Component({
selector: 'my-nav',
template:`
<div class="nav-item" (click)="selectedNavItem(1)">item 1 (click me)</div>
`,
})
export class Navigation {
constructor(private navService:NavService) {}
selectedNavItem(item: number) {
console.log('selected nav item ' + item);
this.navService.emit(item);
}
}
If you try the Plunker, there are a few things I don't like about this approach:
ObservingComponent needs to unsubscribe when it is destroyed
we have to pass the component to subscribe() so that the proper this is set when the callback is called
Update: An alternative that solves the 2nd bullet is to have the ObservingComponent directly subscribe to the navchange EventEmitter property:
constructor(private navService:NavService) {
this.subscription = this.navService.navchange.subscribe(data =>
this.selectedNavItem(data));
}
If we subscribe directly, then we wouldn't need the subscribe() method on the NavService.
To make the NavService slightly more encapsulated, you could add a getNavChangeEmitter() method and use that:
getNavChangeEmitter() { return this.navchange; } // in NavService
constructor(private navService:NavService) { // in ObservingComponent
this.subscription = this.navService.getNavChangeEmitter().subscribe(data =>
this.selectedNavItem(data));
}
You can use either:
Behaviour Subject:
BehaviorSubject is a type of subject, a subject is a special type of observable which can act as observable and observer
you can subscribe to messages like any other observable and upon subscription, it returns the last value of the subject
emitted by the source observable:
Advantage: No Relationship such as parent-child relationship required to pass data between components.
NAV SERVICE
import {Injectable} from '#angular/core'
import {BehaviorSubject} from 'rxjs/BehaviorSubject';
#Injectable()
export class NavService {
private navSubject$ = new BehaviorSubject<number>(0);
constructor() { }
// Event New Item Clicked
navItemClicked(navItem: number) {
this.navSubject$.next(number);
}
// Allowing Observer component to subscribe emitted data only
getNavItemClicked$() {
return this.navSubject$.asObservable();
}
}
NAVIGATION COMPONENT
#Component({
selector: 'navbar-list',
template:`
<ul>
<li><a (click)="navItemClicked(1)">Item-1 Clicked</a></li>
<li><a (click)="navItemClicked(2)">Item-2 Clicked</a></li>
<li><a (click)="navItemClicked(3)">Item-3 Clicked</a></li>
<li><a (click)="navItemClicked(4)">Item-4 Clicked</a></li>
</ul>
})
export class Navigation {
constructor(private navService:NavService) {}
navItemClicked(item: number) {
this.navService.navItemClicked(item);
}
}
OBSERVING COMPONENT
#Component({
selector: 'obs-comp',
template: `obs component, item: {{item}}`
})
export class ObservingComponent {
item: number;
itemClickedSubcription:any
constructor(private navService:NavService) {}
ngOnInit() {
this.itemClickedSubcription = this.navService
.getNavItemClicked$
.subscribe(
item => this.selectedNavItem(item)
);
}
selectedNavItem(item: number) {
this.item = item;
}
ngOnDestroy() {
this.itemClickedSubcription.unsubscribe();
}
}
Second Approach is Event Delegation in upward direction child -> parent
Using #Input and #Output decorators parent passing data to child component and child notifying parent component
e.g Answered given by #Ashish Sharma.
If one wants to follow a more Reactive oriented style of programming, then definitely the concept of "Everything is a stream" comes into picture and hence, use Observables to deal with these streams as often as possible.
you can use BehaviourSubject as described above or there is one more way:
you can handle EventEmitter like this:
first add a selector
import {Component, Output, EventEmitter} from 'angular2/core';
#Component({
// other properties left out for brevity
selector: 'app-nav-component', //declaring selector
template:`
<div class="nav-item" (click)="selectedNavItem(1)"></div>
`
})
export class Navigation {
#Output() navchange: EventEmitter<number> = new EventEmitter();
selectedNavItem(item: number) {
console.log('selected nav item ' + item);
this.navchange.emit(item)
}
}
Now you can handle this event like
let us suppose observer.component.html is the view of Observer component
<app-nav-component (navchange)="recieveIdFromNav($event)"></app-nav-component>
then in the ObservingComponent.ts
export class ObservingComponent {
//method to recieve the value from nav component
public recieveIdFromNav(id: number) {
console.log('here is the id sent from nav component ', id);
}
}
You need to use the Navigation component in the template of ObservingComponent ( dont't forget to add a selector to Navigation component .. navigation-component for ex )
<navigation-component (navchange)='onNavGhange($event)'></navigation-component>
And implement onNavGhange() in ObservingComponent
onNavGhange(event) {
console.log(event);
}
Last thing .. you don't need the events attribute in #Componennt
events : ['navchange'],
I found out another solution for this case without using Reactivex neither services. I actually love the rxjx API however I think it goes best when resolving an async and/or complex function. Using It in that way, Its pretty exceeded to me.
What I think you are looking for is for a broadcast. Just that. And I found out this solution:
<app>
<app-nav (selectedTab)="onSelectedTab($event)"></app-nav>
// This component bellow wants to know when a tab is selected
// broadcast here is a property of app component
<app-interested [broadcast]="broadcast"></app-interested>
</app>
#Component class App {
broadcast: EventEmitter<tab>;
constructor() {
this.broadcast = new EventEmitter<tab>();
}
onSelectedTab(tab) {
this.broadcast.emit(tab)
}
}
#Component class AppInterestedComponent implements OnInit {
broadcast: EventEmitter<Tab>();
doSomethingWhenTab(tab){
...
}
ngOnInit() {
this.broadcast.subscribe((tab) => this.doSomethingWhenTab(tab))
}
}
This is a full working example:
https://plnkr.co/edit/xGVuFBOpk2GP0pRBImsE

Angular2: Accessing child nodes from a template

I have a component and I would like accessing some child nodes from the template. I achieved to access the details div, but I don't know why the code works. What exactly does the Future class? And why the first line prints null? Is this the correct way to access child nodes from the template?
#Component(selector: 'hero-detail', template: '<div #details></div>')
class HeroDetailComponent implements OnInit {
Hero hero;
#ViewChild('details')
var details;
Future ngOnInit() async {
// why this command prints null?
print(details);
// why this command prints "Instance of 'ElementRef_'"
new Future(() => print(details));
}
}
#Component(selector: 'hero-detail', template: '<div #details></div>')
class HeroDetailComponent implements OnInit {
Hero hero;
// Angular generates additional code that looks up the element
// from the template that has a template variable `#details
// and assigns it to `var details`
#ViewChild('details')
var details;
// I don't think Future does anything here.
Future ngOnInit() async {
// why this command prints null?
// this is too early. `#ViewChild()` is only set in `ngAfterViewInit`
// at this point the view is not yet fully created and therefore
// `#details can't have been looked up yet
print(details);
// why this command prints "Instance of 'ElementRef_'"
// this delays `print(details)` until the next Dart event loop
// and `details` is then already lookup up and assigned
new Future(() => print(details));
}
// this is the right place
// needs `class HeroDetailComponent implements OnInit, AfterViewInit {
ngAfterViewInit() {
print(details);
}
}

Resources