Angular ActionCable call method in component when notification received - ruby-on-rails

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)
});

Related

How can I increase the performance when get shared large number of records in a web application MVC, Angular 2

Maybe its a general question , but I really don't know how to find the best solution.In my website, I need to have a select of all companies and subsets in a tree-mode component(this returns a large number of records), almost 80% of my pages needs to be filtered by company-Id (which can be selected by user , or a default value).
Question:
I use Angular2,MVC and EF in my project , Is there any way to reduce these request numbers ?since data security is very important to me, is using sessions or similar option proper for me?
Any help or address to a solution would be appreciated.
Since there's no code to relate, I can only give you a generic answer.
Based on your comment.
You would create a service class for example CompanyService
#Injectable()
export class CompanyService {
constructor(private http: Http) { }
private url: string = 'http://yourapiurl/';
getCompanies(): Observable<ICompany[]> {
return (this.http.get(this.url + 'api/company')
.map((response: Response) => {
return <ICompany[]>response.json();
})
.publishReplay(1)
.refCount()
.catch(CompanyService.handleError)) as any;
}
private static handleError(error: Response) {
console.error(error);
return Observable.throw(error.json().error || 'Server error');
}
}
From there you can inject the service into your components depending where you would need them. For example you need to get the data on your HomeComponent, you would inject the service.
#Component({
selector: 'app-home',
templateUrl: 'home.component.html',
styleUrls: ['home.component.scss']
})
export class HomeComponent implements OnInit {
constructor(private companyService: CompanyService) {
}
companies: ICompany[];
ngOnInit(): void {
this.companyService.getCompanies()
.subscribe(
(companies: ICompany[]) => {
this.companies = companies;
});
}
}
Hope that helps...
UPD
Caching using .publishReplay(1).refCount();

Angular 2 output from router-outlet

I want to make navigation from child components that render inside router-outlet.
My parent component have a router config and I want to navigate manually on some event. But I don't know how I can pass from child to parent some data (for navigation) without output. Because this construction is non working
<router-outlet (navigateTo)="navigateToMessagePart($event)"></router-outlet>
How I can do it in right way? Maybe navigate it from child? But how I can get parent methods from child.
Many thanks for any help!
<router-outlet></router-outlet> can't be used to emit an event from the child component. One way to communicate between two components is to use a common service.
Create a service
shared-service.ts
import { Observable } from "rxjs/Observable";
import { Injectable } from "#angular/core";
import { Subject } from "rxjs/Subject";
#Injectable()
export class SharedService {
// Observable string sources
private emitChangeSource = new Subject<any>();
// Observable string streams
changeEmitted$ = this.emitChangeSource.asObservable();
// Service message commands
emitChange(change: any) {
this.emitChangeSource.next(change);
}
}
Now inject the instance of the above service in the constructor of both the parent and child component.
The child component will be emitting a change every time the onClick() method is called
child.component.ts
import { Component } from "#angular/core";
#Component({
templateUrl: "child.html",
styleUrls: ["child.scss"]
})
export class ChildComponent {
constructor(private _sharedService: SharedService) {}
onClick() {
this._sharedService.emitChange("Data from child");
}
}
The parent component shall receive that change. To do so,capture the subscription inside the parent's constructor.
parent.component.ts
import { Component } from "#angular/core";
#Component({
templateUrl: "parent.html",
styleUrls: ["parent.scss"]
})
export class ParentComponent {
constructor(private _sharedService: SharedService) {
_sharedService.changeEmitted$.subscribe(text => {
console.log(text);
});
}
}
<router-outlet></router-outlet> is just a placeholder for adding routed components. There is no support for any kind of binding.
You can create a custom <router-outlet> that allows you to do that or more common, use a shared service to communicate between parent component and routed component.
For more details see https://angular.io/docs/ts/latest/cookbook/component-communication.html
update
There is now an event that allows to get the added component
<router-outlet (activate)="componentAdded($event)" (deactivate)="componentRemoved($event)"></router-outlet>
which allows to communicate (call getters, setters, and methods) with the component in componentAdded()
A shared service is the preferred way though.
The answer given above is correct and complete. I just want to add for those who the solution didn't work for them that they should add the service to providers only in the parent component and not the child to ensure that you get a singleton of the service, otherwise two service instances will be created.
This response is inspired by the comment of #HeisenBerg in the previous response.
I changed a little from Antara Datta's answer.
I created a Subscriber service
import {Injectable} from '#angular/core';
import {Subject} from 'rxjs';
#Injectable({
providedIn: 'root'
})
export class Subscriber<T>
{
protected observable = new Subject<T>();
public next(item: T)
{
this.observable.next(item);
}
public subscribe(callback: (item:T)=>void) {
this.observable.subscribe(callback);
}
}
Whenever I need two components to share some information, I inject this service in the constructor which subscribe to it:
constructor(protected layoutOptions: Subscriber<Partial<LayoutOptions>>)
{
layoutOptions.subscribe(options => this.options = Object.assign({}, this.options, options));
}
and the one which updates it
constructor(protected router: Router, protected apiService: ApiService, protected layoutOptions: Subscriber<Partial<LayoutOptions>>)
{
this.layoutOptions.next({showNavBar: false});
}
It escapes my understanding why the router does not forward the "#Outputs".
I ended up dispatching barebones DOM events
// dom node needs to be a reference to a DOM node in your component instance
// preferably the root
dom.dispatchEvent(
new CustomEvent('event', {
detail: payload, // <- your payload here
bubbles: true,
composed: true,
})
);
You can catch it anywhere up the DOM tree like any other DOM event
Note: you need to unpack the payload from { detail: payload } on the receiving end..

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 CanActivate with http

I am having a component that has canactivate
import {isLoggedIn} from '../login/isLoginedIn';
#CanActivate((next, previous) => {
isLoggedIn()
})
My "isLoggedIn" is as below
import {Http, Headers} from 'angular2/http';
class Auth {
constructor( #Inject(Http) private _http: Api) { }
check() {
this._http.get('/Users/LoggedInUser')
}
}
export const isLoggedIn = () => {
let injector = Injector.resolveAndCreate([Auth, Http]);
let auth = injector.get(Auth);
return auth.check();
};
I can't inject a service which has http as dependancy. Can this be done like this or is there a better way to do it?
Since the CanActivate is a decorator instead of a method as with OnActivate or CanDeactivate then you are correct in assuming that constructor dependency injection of the component that you are attempting to authorize is not an option.
The method which you are using will work, but there is a missed #Injectable() on your Auth class.
import {Injectable} from 'angular2/core';
import {Http, Headers} from 'angular2/http';
#Injectable()
class Auth {
constructor( #Inject(Http) private _http: Api) { }
check() {
this._http.get('/Users/LoggedInUser')
}
}
This approach is sound and I don't think that besides some syntactic sugar or minor refactoring that there would be much to improve this and still achieve the same amount of readability / maintainability for this approach.
One other addition that could be made to improve the flow and prevent a potential bug would be to return the observable in CanActivate so that the navigation will wait for the Http request to complete before deciding to continue or cancel.
#CanActivate((next, previous) => {
return isLoggedIn()
})
or for short
#CanActivate(() => isLoggedIn())
(Single statement arrow functions are auto-returning)

angular2 inject a service to other - error when using #Inject [duplicate]

This question already has answers here:
Angular2 Beta dependency injection
(3 answers)
Closed 7 years ago.
I am using angular2 Beta. and getting error when using the #Inject annotation to DI my one service to another, not able to figure out where I am wrong. Everything seem to be as per Angular2 documentation.
I am using a cloud based data-services - CloudDB - for my application's data needs.
CloudDB gives me a javascript based client library that I can include in my js app and use to do CRUD operations in my cloudDB database or call other custom API I have stored in my CloudDB account, like UserAuth API (API to authenticate user's credentials).
Before using cloudDB js client lib API , I need to supply my cloudDB account's URL and authKey by calling CloudDB js object's getClient method.
In my angualar2 app, I created a injectable service class - CloudDBProvider - the would store my CloudDB account URL and authKey and call CloudDB.getClient to set the provider's js client object for my CloudDB account.
import {Injectable} from 'angular2/angular2';
///<reference path="../typeDefs/CloudDB.d.ts" /> //typedef of CloudDB js library
#Injectable()
export class CloudDBProvider {
private cloudDBClient: CloudDB.JSClient;
public get cloudDBClient(): CloudDB.JSClient {
return this.cloudDBClient;
}
constructor() {
this.cloudDBClient = new CloudDB.getClient(
"https://myaccount.CloudDB.com/",
"AcfdsfmyDdCMHeadfsdsdfHdsf68" // account authKey
);
}
}
Now, I want to create a UserUtils service in this angular2 app, to which I want to inject above class to get cloudDBClient object. I coded UserUtils service class like below, as learnt from your tutorial
import {Injectable, Inject} from 'angular2/angular2';
import {CloudDBProvider} from './CloudDBProvider';
#Injectable()
export class UserUtils {
private _userDetails: Object = {};
private _cloudDBProvider: CloudDBProvider;
private _cloudDBClient: Microsoft.WindowsAzure.MobileServiceClient;;
constructor( #Inject(CloudDBProvider) cloudDBPrvdr: CloudDBProvider) {
this._cloudDBProvider = cloudDBPrvdr;
this._cloudDBClient = this._cloudDBProvider.cloudDBClient; //the public getter property in the class CloudDBProvider
}
public authenicateUser(p_strUserName: string, p_strUserPassword: string) {
var p: Promise<any> = new Promise(
(resolve: (result: any) => void, reject: (err: any) => void) =>
this._cloudDBClient.userlogin(p_strUserName, p_strUserPassword).done( //using API 'userlogin' of cloudDB to authenticate user against my cloudDB's users table.
(loginResult) => {
alert("from Userutils - You are now logged in as: " + loginResult.user.basicProfile.firstName);
resolve(loginResult);
},
(loginErr: any) => {
alert("Error: " + loginErr.request.responseText);
reject(loginErr);
}
)
);
return p;
}
}
then I am trying to use UserUtils in my LoginPage component like below:
import {Component} from 'angular2/core';
import {WelcomePage} from "../views/welcome/welcome";
import {UserUtils} from "../services/UserUtils";
#Component({
templateUrl: 'app/login/login.html',
providers: [UserUtils]
})
export class LoginPage {
private _userUtils: UserUtils;
constructor( userUtils: UserUtils) {
this._userUtils = userUtils;
}
public loginButtonClicked(event, userName, password) { //called when Login Button is clicked by user
//...
//... to-do field value verification
//...
this._userUtils.authenicateUser(userName, password).then(
(result) => {
//navigate to WelcomePage
},
(err) => { alert(err); }
);
}
}
the component LoginPage doesn't work when I use UserUtils. The browser console throws error - No provider for CloudDBProvider! (LoginPage -> UserUtils -> CloudDBProvider)
Note that, if I move the 'authenicateUser' method from UserUtils to CloudDBProvider directly and use CloudDBProvider in LoginPage component for user authentication, then everything works just fine, user gets authenticated and navigated to welcome page after login. Also, no error is thrown and app working if I remove #Inject(CloudDBProvider) cloudDBPrvdr from UserUtils's constructor obviously I cannot use CloudDBProvider then in UserUtils, but point is app doesn't throw any error, which means something is wrong with #Inject.
any clue where I am going wrong?
Upto my Understanding your mistake is in the imports change the import of Injectablewith this
import {Component, Inject, Injectable} from 'angular2/core';
also accoriding to me when we have used #injectable annotation no need to use #inject in the constructor you simply put your service with the public identifier and can use that service into any another method of the same class.
Perhaps you could add the CloudDBProvider provider in the list of providers of your component:
#Component({
templateUrl: 'app/login/login.html',
providers: [UserUtils, CloudDBProvider]
})
export class LoginPage {
(...)
}
Or at application level within the second parameter of the bootstrap function:
bootstrap(MainComponent, [CloudDBProvider]);
This answer could give you some additional hints: Angular2 Beta dependency injection.
Hope it helps you,
Thierry

Resources