1

I'm pretty sure it's my fault, but I can't spot it.

I created a new Ionic/Angular app with ionic start oracolo and then I added a new component to it (named Histogram, though that does not really matter). Then I installed vega-embed with npm install vega-embed and tried to add a Vega/Vega-Lite view into my component using this code:

 async ngOnInit() {
    const spec = "https://raw.githubusercontent.com/vega/vega/master/docs/examples/bar-chart.vg.json";
    const result = await embed("figure#vis", spec);
    console.log(result.view);
  }

paired with its HTML template:

<div>
  <figure id="vis"></figure>
</div>

I think what I have done here is just follow the example code on the vega-embed project page, however when I run my app no Vega view appears and I get the following error in my browser console:

Uncaught (in promise): Error: figure#vis does not exist
Error: figure#vis does not exist
    at _callee4$ (vega-embed.module.js:2960:17)
    at tryCatch (vega-embed.module.js:123:15)
    at Generator.invoke [as _invoke] (vega-embed.module.js:319:20)
    at prototype.<computed> [as next] (vega-embed.module.js:172:19)
    at asyncGeneratorStep (vega-embed.module.js:54:24)
    at _next (vega-embed.module.js:73:9)
    at vega-embed.module.js:78:7
    at new ZoneAwarePromise (zone.js:1429:21)
    at vega-embed.module.js:70:12
    at _embed3 (vega-embed.module.js:3227:18)
    at resolvePromise (zone.js:1211:31)
    at zone.js:1118:17
    at zone.js:1134:33
    at rejected (tslib.es6.js:119:89)
    at _ZoneDelegate.invoke (zone.js:372:26)
    at Object.onInvoke (core.mjs:24313:33)
    at _ZoneDelegate.invoke (zone.js:371:52)
    at Zone.run (zone.js:134:43)
    at zone.js:1275:36
    at _ZoneDelegate.invokeTask (zone.js:406:31)

I'm not sure if the app being a Ionic app could make any difference from the vega-embed point of view, so I brought it to you as is. What am I doing wrong?

EDITED after E.Maggini's answer:

I've tried moving the code to ngAfterViewInit, where the DOM is supposedly available, but I'm getting the same error:

export class HistogramComponent implements OnInit, AfterViewInit {

  constructor() { }

  ngOnInit() { }

  async ngAfterViewInit() {
    const spec = "https://raw.githubusercontent.com/vega/vega/master/docs/examples/bar-chart.vg.json";
    const result = await embed("figure#vis", spec);
    console.log(result.view);
  }
}

EDIT 2:

Adding the Vega view to the pre-existing ExploreContainerComponent that was autogenerated by the ionic start command DOES work. Adding the view to the HistogramComponent I generated afterwards does NOT work.

However I can't see any differences between the two components, except their name.

Lucio Crusca
  • 1,277
  • 3
  • 15
  • 41

2 Answers2

2

This is a lifecycle issue. OnInit the DOM is not available.

Use AfterViewInit.

1

In the end the problem was totally unrelated to vega-embed, but was being caused by a mistake in how I was including my custom component into the tab, and this code wasn't shown in my question:

tab3.page.html, before I found the mistake:

<app-explore-container name="Tab 3 page">
  <histogram></histogram>
</app-explore-container>

tab3.page.html, after the fix:

<app-explore-container name="Tab 3 page">
</app-explore-container>

<histogram></histogram>

Problem here is that app-explore-container is a custom component that does not support projected content (it lacks ng-content in its template), so nesting anything into it while in an external template (tab3.page.html) won't work.

The same goes for any custom component I created so far in my life, but for some weird reason I instinctively nested my histogram into app-explore-container taking for granted it would have behaved just like any other HTML tag.

With reference to E.Maggini's answer, I even tried moving the code back into ngOnInit and it does work, so while this was actually a lifecycle issue as suggeted, because projected content issues are such, and while it's likely true that the DOM isn't available during the OnInit phase, I guess that does not make any difference, because of the async nature of the embed function, which is not executing its code during ngOnInit, but as soon as it can.

Lucio Crusca
  • 1,277
  • 3
  • 15
  • 41