0

service.ts:

  private showBoxAction = new Subject<any>();
  showBox = this.showBoxAction.asObservable();
  openBox() {
    console.log("in Box");

    this.showBoxAction.next(true);
  }

Component1.html

 <ng-template #noMsgs>
                  <div id="top" class="container">
                    <div class="row">
                      <div class="col-xs-12 explorer-results">
                        <div class="no-results-found">
                          <div class="joinUs">
                                <span>
                                  <p >Join us.</p>
                                  <a href="javascript:" (click)="showBox()" class="mat-button default">Start Now</a>
                                </span>
                            </div>
                        </div>
                      </div>
                    </div>
                  </div>
                </ng-template>

component1.ts

      providers: [, DatePipe, FragmentParamsPipe],
import { environment } from "./../../../../environments/environment";
import { Http, ConnectionBackend } from "@angular/http";
import {
  Component,
  OnInit,
  OnDestroy,
  AfterViewInit,
  HostListener,
  Inject,
  NgZone,
  ViewChild,
  ElementRef,
  Output
} from "@angular/core";
import { DOCUMENT, Title } from "@angular/platform-browser";


import { Subscription } from "rxjs/Subscription";
import {
  CONSTANT,
  FEATURE,
  flattenJSON,
  unflattenJSON
} from "../../../Constants";
import { Observable } from "rxjs/Observable";
import { MatDialog, MatDialogRef } from "@angular/material";
import { BehaviorSubject } from "rxjs/BehaviorSubject";
import { Subject } from "rxjs/Subject";
import { Router, NavigationEnd, ActivatedRoute } from "@angular/router";
import { TabsetComponent } from "ngx-bootstrap";
import { Service } from "/src/app/services/service";
import { FragmentParamsPipe } from "../../../pipes/url/fragment-params.pipe";

declare let jQuery: any;
@Component({
  selector: "component1",
  templateUrl: "./component1.component.html",
  styleUrls: ["./component1.component.css"],
  providers: [QuestionControlService, DatePipe, FragmentParamsPipe],
  entryComponents: [DialogBoxComponent, MasterListComponent]
})
export class UserProfileComponent implements OnInit, OnDestroy, AfterViewInit {

  constructor(
    @Inject(DOCUMENT) private document: Document,
    private _service: Service,

  ) {


  }

  ngOnInit() {

  }


  /**
   * Display messageBox component.
   */
  showBox() {
      this._service.openComposeBox();
  }

  ngAfterViewInit() {

  }



  ngOnDestroy(): void {
  }




  }

Component2.ts

 private subscriptions = new Subscription();

  constructor(private _service:Service)
{

    this.subscriptions.add(
      this._service.showBox.subscribe(event => {
        if (event) {

        console.log("display box");
        }
      })
    );
}

When I click on show-box to trigger showBox() function I get output in console "in Box" but I do not get console "display box" i.e observable is not subscribed. What could be the reason where as when my next trigger calls openBox() then observable subscribes successfully. What is wrong with my implementation?

UPDATE

Problem is only when I call it through component1.ts and it is first time in app when I use it. I have tried subscribing without adding it into subscription.

component2.ts

 ngOnInit() {
    this._service.showBox.takeUntil(this.destroy$).subscribe(event => {

      if (event) {
        this.displayCompose = true;
        console.log("display box");
      }
    })

  }



 ngOnDestroy(): void {

    this.destroy$.next(true);
    // Now let's also unsubscribe from the subject itself:
    this.destroy$.unsubscribe();

    this.subscriptions.unsubscribe();
  }
}

UPDATE

Structure of my app and components I have referred in post: my-angular-app\src\app\components\component1\componen1.ts

my-angular-app\node_modules\angular-app2\components\component2-parent\component2-parent.ts

my-angular-app\node_modules\angular-app2\components\component2\component2.ts Component1.component.html:

     <ng-template #noMsgs>
                      <div id="top" class="container">
                        <div class="row">
                          <div class="col-xs-12 explorer-results">
                            <div class="no-results-found">
                              <div class="joinUs">
                                    <span>
                                      <p >Join us.</p>
                                      <a href="javascript:" (click)="showBox()" class="mat-button default">Start Now</a>
                                    </span>
                                </div>
                            </div>
                          </div>
                        </div>
                      </div>
                    </ng-template>

<component2-parent *ngIf="display"></component2-parent>

component1.ts

export class Component1 
showBox()
{
this.display = true;
_service.openBox()
}

component2-parent contains component2.

Always_a_learner
  • 4,585
  • 13
  • 63
  • 112
  • Maybe some previous subscription, added in `subscriptions` was unsubscribed and the whole chain is done - you can't add more other subscriptions to it. Maybe you used an operator like `first()`, `takewhile` etc. - they unsubscribe after condition is met – Julius Dzidzevičius Jul 14 '18 at 16:43
  • Are you sure both components access the same service instance? Make sure you are not providing the service in the component metadata in the providers array. – SirDieter Jul 14 '18 at 17:35
  • @SirDieter I am 100% sure. As I am using IDE and it is taking me to same place. – Always_a_learner Jul 14 '18 at 20:18
  • @yourFather I have added an update wherein I have tried it with takeUntil, still same issue. – Always_a_learner Jul 14 '18 at 20:19
  • It's not about the class it's about the class instance – SirDieter Jul 14 '18 at 20:53
  • @SirDieter Can you please explain, it might help me. – Always_a_learner Jul 14 '18 at 20:55
  • Do you have the service in one of the components in @Component({ blabla..., providers: [Service])? – SirDieter Jul 14 '18 at 21:22
  • @SirDieter No I am adding service as dependency Injection only. – Always_a_learner Jul 14 '18 at 21:23
  • @Simer, In your component1 and 2 you wrote this._service and you object is showBoxAction , in your update you wrote this._mailingService and your object is showComposeBox , there is inconsistent in your code, please edit your topic with your last modifications. – dAxx_ Jul 14 '18 at 21:28
  • @dAxx_ Done. Please check I have updated my update. – Always_a_learner Jul 14 '18 at 21:31
  • okay, @Simer, Can you provide a little bit more background about what are you trying to do ? I assume because of the names that you are trying to open a modal maybe? or anything? let me see a little bit of your HTML wrapper of this div so I get a little bit more information. – dAxx_ Jul 14 '18 at 21:35
  • @dAxx_ As evident, I have to components which are grandparent and grandChild relation. I have to click on a link which would send an event to observable and after receiving an event I would set a property value true which would show a div. It is not a modal, it is just another html within component2 which I want to show up after setting displayCompose true. I have updated my post html part. Thanks for your time. :) – Always_a_learner Jul 14 '18 at 21:50
  • Okay, and you also wrote: Problem is only when I call it through component1.ts and it is first time in app when I use it. so it means thats if you click twice it works ? – dAxx_ Jul 14 '18 at 21:53
  • @dAxx_ It never works from component1.ts, I wrote about first time to clarify that subject is not holding any previous value. – Always_a_learner Jul 14 '18 at 21:56
  • wheres your component2 placed in the html? – dAxx_ Jul 14 '18 at 22:28
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/176015/discussion-between-simer-and-daxx). – Always_a_learner Jul 15 '18 at 15:02

2 Answers2

2

Use BahaviourSubject, so that you do not miss out the initial value,

private showBoxAction = new BehaviorSubject <any>();

and also add your subscription inside ngOnInit() (good practice) as opposed to constructor.

ngOnInit() {
  this._service.showBox.subscribe(event => {
    if (event) {
      this.displayCompose = true;

    console.log("display box");
    }
  })
Amit Chigadani
  • 28,482
  • 13
  • 80
  • 98
  • https://stackoverflow.com/questions/51318977/subscribing-to-observable-even-when-next-is-not-called-on-behaviorsubject This the problem I was facing when I used behavior subject. subcribing even when next is not triggered. thanks for help! But I need better solution. – Always_a_learner Jul 14 '18 at 16:21
  • What is the reason to use subscription.add()? Not sure if that is the problem – Amit Chigadani Jul 14 '18 at 16:30
  • to Unsubscribe all the subscriptions on ngDestroy(). private subscriptions = new Subscription(); – Always_a_learner Jul 14 '18 at 16:30
  • Amit Chigadani can you tell me when we want to subscribe to an observable on loading a component to check something then should we do it in ngOnit or constructor? I have read about lifecyclehooks but could not understand the right usage. – Always_a_learner Jul 15 '18 at 11:20
  • 1
    `constructor` is `typescript` stuff which should be used only for initialization. `ngOnInit` is angular life cycle event which should contain things like `subscriptions` to Observables. Because in few cases, your component constructor might run before service gets initialized which could lead to an error. So you should stick to `OnInit()`. Always try to utilize angular life cycle hooks. – Amit Chigadani Jul 15 '18 at 11:24
  • And `this._mailingService.openComposeBox();`, should not that be `this._service.openComposeBox();`? – Amit Chigadani Jul 15 '18 at 11:35
  • I have corrected, it was a mistake I did while writing code here, in actual source it does not exist. – Always_a_learner Jul 15 '18 at 11:51
  • Probably your service is not a singleton. Means comp1 and comp2 are not sharing the same instance. You have to provide `service` at the module level (and not inside the component) in which your comp1 and comp2 exist. – Amit Chigadani Jul 15 '18 at 13:03
  • Amit Chigadani if that was the case then my control should not reach to service. I am getting in console output what I log inside openBox() therefore instance must be same. – Always_a_learner Jul 15 '18 at 14:44
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/176014/discussion-between-amit-chigadani-and-simer). – Amit Chigadani Jul 15 '18 at 14:46
0

Okay, let‘s try it another way.

Instead of this line of code in your service.ts

showBox = this.showBoxAction.asObservable();

put this method

getShowBoxAction(): Observable<any> {
   return this.showBoxAction.asObservable();
}

And in your component2.ts subscribe this way

// of course you can add this to your subscriptions-object as well.
this._service.getShowBoxAction().subscribe( event => {

    // the rest of your code

});

Edit: 15. July 2018 1.29 pm

You do not call the right service. This is what you currently call in component1:

// **
   * Display messageBox component.
   */
    showBox() {
        this._mailingService.openComposeBox();
    }

But you have to call your service.ts!

showBox() {
    this._service.openBox();
}

Please replace the code any give it a try.

  • Okay, here is another approach. Please try it. –  Jul 14 '18 at 21:12
  • DiabolicWords tried it. I am going inside getShowBoxAction() where I have logged some msg, but not subscribed to function. So I think it did not work. Thanks alot for your intrest and time. Let me know if there could be any other solution. – Always_a_learner Jul 14 '18 at 21:55
  • Diabolic Words What I logged inside getShowBoxAction got console thrice, whereas It should get console once. What could be the reason? – Always_a_learner Jul 14 '18 at 22:01
  • Three times seems odd to me. It‘s pretty normal that the subscription itself triggers directly a first run during establishment, but then there should only be a second logging when you click the button. –  Jul 15 '18 at 06:39
  • Okay, thought about it. The problem seems to originate from component1. I still wonder why a simple click never reaches its target method. Did you maybe use a mock for this service? Maybe you still call the mock without noticing it? Or do you have further services injected that carry almost the same name and you mixed them up? —- By the way: How do you subscribe to the service in component1? Please post your TS-File of component1 too. –  Jul 15 '18 at 07:06
  • DiabolicWords Sorry it was while writing code for this post, in actual code this issue does not exist. Thanks again! – Always_a_learner Jul 15 '18 at 11:41