angular 2 problem setting an object inside a subscribe section

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.
LVL 1
derridaAsked:
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

x
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Julian HansenCommented:
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?
0
derridaAuthor 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.
0
Julian HansenCommented:
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 ?
0
Big Business Goals? Which KPIs Will Help You

The most successful MSPs rely on metrics – known as key performance indicators (KPIs) – for making informed decisions that help their businesses thrive, rather than just survive. This eBook provides an overview of the most important KPIs used by top MSPs.

derridaAuthor 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
0
Julian HansenCommented:
So what you are saying is the .subscribe() is not actually firing?
0
derridaAuthor 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.
0
Julian HansenCommented:
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.
0
derridaAuthor 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.
0
Julian HansenCommented:
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.
0
derridaAuthor 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).
0
Julian HansenCommented:
Then you have to take it out of afterViewInit and call the setAll in the .subscribe - after the .http.get call completes.
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
derridaAuthor 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
0
Julian HansenCommented:
Have you tried setting the title by just doing this
document.title = "this.meta['title']";

Open in new window

0
derridaAuthor Commented:
thanks for the great help!!
0
Julian HansenCommented:
You are welcome.
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
JavaScript

From novice to tech pro — start learning today.