angular 2 problem setting an object inside a subscribe section

derrida
derrida used Ask the Experts™
on
hi
i get the id of a post from the url, then getting the post contents. then i want to set my meta object . that is the logic but it does,'t work inside the subscribe, while it does outside of it. it is async so how can i set the meta object, populate it?
this is the entire component code:
import { Component, OnInit,OnDestroy,AfterViewInit,Renderer } from '@angular/core';
import { Router, ActivatedRoute } from '@angular/router';
import { Subscription } from 'rxjs/RX';
import {AppService} from '../services/app.service';
import { MetaSetterService } from '../services/meta-setter.service';

@Component({
  selector: 'app-post',
  templateUrl: './post.component.html',
  styleUrls: ['./post.component.css']
})
export class PostComponent implements OnInit,OnDestroy,AfterViewInit {

  subscription: Subscription;
  postId:String;
  thepost;
  meta:Object = {};
  post;
  postTitle:String;

  constructor(
    private router: Router, 
    private activeR: ActivatedRoute,
    private as:AppService,
    private metaSetter:MetaSetterService,
    public renderer:Renderer
  ) {
    
    this.subscription = this.activeR.params.subscribe(
      (param:any) => {
        this.postId = param['id'];
      }
    )
   }

  ngOnInit() { 
    this.as.getPostById(this.postId).subscribe(
      (post) => {
        this.thepost = post;
        console.log(this.thepost);
        this.postTitle = post.title;
        this.meta['title'] = 'title of the post';
        this.meta['metaTitle'] = 'meta tag title';
        this.meta['metaDesc'] = 'dynamic description for post';
        this.meta['metaKeywords'] = 'dynamic,keywords,post';
        this.meta['ogTitle'] = 'post title';
        this.meta['ogDesc'] = 'dynamic description to share post';
        this.meta['ogImg'] = '/assets/images/postimage.jpg';
        this.meta['ogUrl'] = '/post/idpost';
      }
    );
    //console.log(this.thepost);
    // this.meta['title'] = 'title of the post';
    // this.meta['metaTitle'] = 'meta tag title';
    // this.meta['metaDesc'] = 'dynamic description for post';
    // this.meta['metaKeywords'] = 'dynamic,keywords,post';
    // this.meta['ogTitle'] = 'post title';
    // this.meta['ogDesc'] = 'dynamic description to share post';
    // this.meta['ogImg'] = '/assets/images/postimage.jpg';
    // this.meta['ogUrl'] = '/post/idpost';
  }



  ngOnDestroy(){
    this.subscription.unsubscribe();
  }

  ngAfterViewInit():void{
    this.metaSetter.setAll(this.renderer,this.meta);
  }


}

Open in new window


and this is the method for getting the post by id:
  getPostById(id:String){
    let url = this.apiURL + '/blog.json';
    return this.http.get(url,{headers:this.headers})
      .map(posts => {
        return posts.json().filter(post => post._id === id)[0];
      })
  }

Open in new window


i'm refering to the code in the ngOnInit. setting the meta inside doesn't work, while outside it does.
Comment
Watch Question

Do more with

Expert Office
EXPERT OFFICE® is a registered trademark of EXPERTS EXCHANGE®
Most Valuable Expert 2017
Distinguished Expert 2018

Commented:
When you say it does not work - do you mean the values are not being assigned or they are not being inserted into the page?

Author

Commented:
Hi Julian
outside of the subscribe block, the are inserted. inside they are not. so either i need the dynamic content to be available outside, or i need to make it work from the indise.
Most Valuable Expert 2017
Distinguished Expert 2018

Commented:
Ok but if I understand your code correctly the meta data has nothing to do with the actual post.

Is the console.log line 40 being rendered ?
Ensure you’re charging the right price for your IT

Do you wonder if your IT business is truly profitable or if you should raise your prices? Learn how to calculate your overhead burden using our free interactive tool and use it to determine the right price for your IT services. Start calculating Now!

Author

Commented:
well, right now it is hard coded. but obviously eventually i will want the data like post.title to be used.
and yeah, within the subscribe logging the result does work.
the log
Most Valuable Expert 2017
Distinguished Expert 2018

Commented:
So what you are saying is the .subscribe() is not actually firing?

Author

Commented:
the subscribe block does give me the specific post data, but if i try to populate the meta object it is not inserted. if i set the meta outside of the subscribe block it does work.
so i need access to this.thepost outside of the subscribe block, so i can use it to populate the meta object.
another option will be if i could populate the meta object within the subscribe block.
as it stand, i can populate it outside, but then i don't have access to this.thepost.
Most Valuable Expert 2017
Distinguished Expert 2018

Commented:
Sorry misread your previous post - where you said the logging does work.

Just explain how the meta object is supposed to "work" - right now all I can see is you are assigning values to an object - what denotes a working condition.

Author

Commented:
i have an empty meta object. then i should populate it, then in the ngAfterViewInit i send it to insert the values. again, if i uncomment the metas outside the subscribe, it is inserted. so i think the most obvious thing to do is to gain access to the this.thepost outside of the subscribe block.
Most Valuable Expert 2017
Distinguished Expert 2018

Commented:
Ok but this is important.

When you do it outside the subscribe it happens in the ngInit.
When you do it inside the subscribe it happens asynchronously when the http.get completes - which is going to be AFTER ngInit completes.

How your code interacts with the META data object is important because if it consumes it directly after ngInit finishes then it will be working on an empty object when meta is populated in the subscribe.

If it is bound to the meta object in a bi-directional manner then updating the meta object should reflect in the view where it is being used.

To answer this I need more information about how the rest of your code that uses meta hangs together.

Author

Commented:
hi Julian
yeah, i get that . but not sure at what stage exactly can i do it. i am playing with angular universal, and for the moment just doing a very simple thing, in order to check how the meta tags can be implemented.
so for now this is my very basic meta service, and it gets the renderer and the meta in the afterViewInit:
import { Injectable,Inject } from '@angular/core';
import { DOCUMENT } from '@angular/platform-browser';

@Injectable()
export class MetaSetterService {

  private renderer:any;

  constructor(@Inject(DOCUMENT) private document:any) { }

  public setAll(renderer:any,meta:Object):void {
    //console.log(meta['title']);
    this.renderer = renderer;
    //console.log(this.document.head.children);
    for(let i = 0; i < this.document.head.children.length; i ++){
      let element = this.document.head.children[i];
      //console.log(element.name);
      if(element.name === 'title'){
        this.renderer.setText(element,meta['title']);
      }
      if(element.name === 'meta' && element.attribs.name === 'title'){
        element.attribs.content = meta['metaTitle'];
      }
      if(element.name === 'meta' && element.attribs.name === 'description'){
        element.attribs.content = meta['metaDesc'];
      }
      if(element.name === 'meta' && element.attribs.name === 'keywords'){
        element.attribs.content = meta['metaKeywords'];
      }
      if(element.name === 'meta' && element.attribs.name === 'og:title'){
        element.attribs.content = meta['ogTitle'];
      }
      if(element.name === 'meta' && element.attribs.name === 'og:description'){
        element.attribs.content = meta['ogDesc'];
      }
      if(element.name === 'meta' && element.attribs.name === 'og:image'){
        element.attribs.content = meta['ogImg'];
      }
      if(element.name === 'meta' && element.attribs.name === 'og:url'){
        element.attribs.content = meta['ogUrl'];
      }
    }
  
  }



}

Open in new window


again, if i set them in the onInit it works, if i set it in the subscribe in the onInit it's not (since async).
Most Valuable Expert 2017
Distinguished Expert 2018
Commented:
Then you have to take it out of afterViewInit and call the setAll in the .subscribe - after the .http.get call completes.

Author

Commented:
ok so this does work but not entirely. this is the current code:
  ngOnInit() { 
    this.as.getPostById(this.postId).subscribe(
      (post) => {
        this.thepost = post;
        //console.log(this.thepost);

        this.meta['title'] = post.title;
        this.meta['metaTitle'] = post.title;
        this.meta['metaDesc'] = post.description;
        this.meta['metaKeywords'] = post.keywords;
        this.meta['ogTitle'] = post.title;
        this.meta['ogDesc'] = post.description;
        this.meta['ogImg'] = '/assets/images/postimage.jpg';
        this.meta['ogUrl'] = '/post/idpost';
      },
      (err) => console.log(err),
      () => {
        this.metaSetter.setAll(this.renderer,this.meta);
      }
    );

  }

Open in new window


the source code does change with each senected post, but the title on the browser tab doesn't until i refresh the browser. but the source code is ok
source code and tab
Most Valuable Expert 2017
Distinguished Expert 2018

Commented:
Have you tried setting the title by just doing this
document.title = "this.meta['title']";

Open in new window

Author

Commented:
thanks for the great help!!
Most Valuable Expert 2017
Distinguished Expert 2018

Commented:
You are welcome.

Do more with

Expert Office
Submit tech questions to Ask the Experts™ at any time to receive solutions, advice, and new ideas from leading industry professionals.

Start 7-Day Free Trial