3 Replies - 252 Views - Last Post: 06 February 2019 - 06:22 AM Rate Topic: -----

#1 andrewsw   User is online

  • quantum multiprover
  • member icon

Reputation: 6778
  • View blog
  • Posts: 27,971
  • Joined: 12-December 12

Angular (2) global value

Posted 22 January 2019 - 08:58 AM

I have an ASP.NET Core, Angular (2) application. [That is, Angular 7, not AngularJS.]

Do you have an idea, or reference(s), of how I can reference a value or service globally?

In a number of components and check if logged in and get the username. I am then using a hack, i.e. jQuery, to show the username in the navbar above the component:

  constructor(private officeService: OfficeService, private hostElement: ElementRef) { }

  ngOnInit() {
    this.officeService.LoggedIn()
      .subscribe(log => {
        if (log.loggedIn) {
          this.userName = log.userName;
          kendo.jQuery('#username').text(' ' + this.userName);

          this.getOffices();
        } else {
          kendo.jQuery('#username').text('Log in');

          window.location.href = '/Identity/Account/Login?ReturnUrl=%2Foffices';
        }
      });
  }

If I can access the loggedIn property and userName I will be able to switch 'log in' to 'log out' and show the username.

I found this link which some of which might be relevant.

What is holding me back slightly is the redirection if the user is not logged in. It looks like I might end up performing the same checking via of service (checking if logged in) for both the navbar and each other component.

Is This A Good Question/Topic? 0
  • +

Replies To: Angular (2) global value

#2 andrewsw   User is online

  • quantum multiprover
  • member icon

Reputation: 6778
  • View blog
  • Posts: 27,971
  • Joined: 12-December 12

Re: Angular (2) global value

Posted 24 January 2019 - 07:40 AM

This is frustrating as it should be straightforward.

I have a menu component, and below it for router-outlet will appear a contacts component, or offices, component, etc.

    <div>
      <app-nav-menu #menu></app-nav-menu>
    </div>
    <div class='col-sm-12 body-content'>
      <router-outlet></router-outlet>
    </div>


The contacts component will check if the user is logged in and whether an administrator. I want a simple property isAdmin in the menu that I can change from the contacts, etc., components from false to true (so that certain links can be hidden).

I added #menu above, believing this gives the component a reference name.

In the nav menu component I just default it to false,
export class NavMenuComponent {
  isExpanded = false;
  isAdmin: boolean = false;

So... in the contacts component I want to be able to refer to the menu, so that I can set its property (or field) isAdmin to true.

Here are the relevant parts I've added:

export class ContactsComponent implements OnInit, AfterViewInit, OnDestroy {
...
  @Input() menu: NavMenuComponent;
...
    ngOnInit() {
        this.menu.isAdmin = true;


But this.menu is undefined. What am I missing so that I can refer to the menu, sibling, component?
Was This Post Helpful? 0
  • +
  • -

#3 andrewsw   User is online

  • quantum multiprover
  • member icon

Reputation: 6778
  • View blog
  • Posts: 27,971
  • Joined: 12-December 12

Re: Angular (2) global value

Posted 24 January 2019 - 09:23 AM

I have to accept that this needs more wiring than I assumed, following this Sharing Data with a Service.

I have an authorised service which I will use in every component:

@Injectable()
export class AuthorisedService {
  private get userUrl() { return environment.apiUrl + '/User' };

  private userNameSource = new behaviorSubject('');
  private isAdminSource = new behaviorSubject(false);

  currentUserName = this.userNameSource.asObservable();
  currentAdminStatus = this.isAdminSource.asObservable();

  constructor(private http: HttpClient) { }

  changeAdminStatus(status: boolean) {
    this.isAdminSource.next(status);
  }
  changeUserName(name: string) {
    this.userNameSource.next(name);
  }

  LoggedIn(): Observable<User> {
    return this.http.get<User>(this.userUrl + '/LoggedIn');
  }
}

I will call LoggedIn from all components (except the navbar), then change the username and admin status each time. The navbar subscribes to these values, so will always reflect their current values:

  constructor(private authorisedService: AuthorisedService) { }

  ngOnInit() {
    this.authorisedService.currentAdminStatus.subscribe(status => this.isAdmin = status);
    this.authorisedService.currentUserName.subscribe(name => this.userName = name);
  }

I can refer to these two values (isAdmin, userName) in the HTML for the navbar, to hide buttons and display the username (if there is one).

For completeness, this is the code in each component that will recheck the current user details:

  ngOnInit() {
    this.authorisedService.LoggedIn()
      .subscribe(log => {
        if (log.loggedIn) {
          this.authorisedService.changeUserName(log.userName);
          this.authorisedService.changeAdminStatus(log.admin);
        } else {
          this.authorisedService.changeUserName('');
          this.authorisedService.changeAdminStatus(false);
        }
      });
  }

It is a bit long-winded but I realise that, of course, I need to check the status from every component, even the initial home/landing page, because the username and admin status always needs to be available and known.
Was This Post Helpful? 0
  • +
  • -

#4 andrewsw   User is online

  • quantum multiprover
  • member icon

Reputation: 6778
  • View blog
  • Posts: 27,971
  • Joined: 12-December 12

Re: Angular (2) global value

Posted 06 February 2019 - 06:22 AM

I am returning to this topic with a slight variation of the question.

In my app.component.html I have a button #popupNotification that is not displayed initially, but is used for a kendoNotification.

<div class='container-fluid'>
  <div class='row'>
    <div>
      <app-nav-menu></app-nav-menu>
      <button id="popupNotification" class="k-button" style="display:none;"></button>
    </div>
    <div class='col-sm-12 body-content'>
      <router-outlet></router-outlet>
    </div>
  </div>
</div>

In another component I can produce the popup message for errors, with a helper function like this:

  private notifyError(defaultText, err) {
    let popupNotification = kendo.jQuery('#popupNotification').kendoNotification().data('kendoNotification');

    if (err)
      popupNotification.show('Error: ' + err, 'error');
    else
      popupNotification.show(defaultText, 'error');
  }

I could, of course, just copy this code into any component that needs a popup message. (The HTML element itself is always available as #popupNotification.)

This isn't the correct, reusable, way to do this. How can I make this a small reusable component? Or should it be some kind of 'service', or 'module'? It is purely a UI feature/component, so I cannot really see how it could be described as 'service' or even if it should be dependency injected?
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1