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.
JavaScript

Avatar of undefined
Last Comment
Julian Hansen

8/22/2022 - Mon
Julian Hansen

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?
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.
Julian Hansen

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 ?
This is the best money I have ever spent. I cannot not tell you how many times these folks have saved my bacon. I learn so much from the contributors.
rwheeler23
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.
the log
Julian Hansen

So what you are saying is the .subscribe() is not actually firing?
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.
Get an unlimited membership to EE for less than $4 a week.
Unlimited question asking, solutions, articles and more.
Julian Hansen

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.
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.
Julian Hansen

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.
Experts Exchange is like having an extremely knowledgeable team sitting and waiting for your call. Couldn't do my job half as well as I do without it!
James Murphy
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
Julian Hansen

Log in or sign up to see answer
Become an EE member today7-DAY FREE TRIAL
Members can start a 7-Day Free trial then enjoy unlimited access to the platform
Sign up - Free for 7 days
or
Learn why we charge membership fees
We get it - no one likes a content blocker. Take one extra minute and find out why we block content.
Not exactly the question you had in mind?
Sign up for an EE membership and get your own personalized solution. With an EE membership, you can ask unlimited troubleshooting, research, or opinion questions.
ask a question
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
source code and tab
Julian Hansen

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

Open in new window

Get an unlimited membership to EE for less than $4 a week.
Unlimited question asking, solutions, articles and more.
derrida

ASKER
thanks for the great help!!
Julian Hansen

You are welcome.