Link to home
Start Free TrialLog in
Avatar of derrida
derrida

asked on

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.
Avatar of Julian Hansen
Julian Hansen
Flag of South Africa image

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?
Avatar of derrida
derrida

ASKER

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.
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 ?
Avatar of derrida

ASKER

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.
User generated image
So what you are saying is the .subscribe() is not actually firing?
Avatar of derrida

ASKER

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.
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.
Avatar of derrida

ASKER

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.
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.
Avatar of derrida

ASKER

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).
ASKER CERTIFIED SOLUTION
Avatar of Julian Hansen
Julian Hansen
Flag of South Africa image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of derrida

ASKER

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
User generated image
Have you tried setting the title by just doing this
document.title = "this.meta['title']";

Open in new window

Avatar of derrida

ASKER

thanks for the great help!!
You are welcome.