vega / vega-embed

Publish Vega visualizations as embedded web components with interactive parameters.
BSD 3-Clause "New" or "Revised" License
390 stars 85 forks source link

Signal bind element not found: null #64

Closed king612 closed 6 years ago

king612 commented 6 years ago

Using the latest versions of vega, vega-lite, and vega-embed with a simple example from you code sample, I get the following console error:

ERROR: Signal bind element not found: null log @ logger.js:3 : (etc)

I'm calling this from within Angular 5 (TypeScript) as follows:

import vegaEmbed from 'vega-embed'; : // statically create a spec object from the samples vlHelloWorld: any = { ... }

In the init function:

vegaEmbed('vega-lite', this.vlHelloWorld, {mode: 'vega-lite'});

Markup:

domoritz commented 6 years ago

That looks like a Vega issue. Can you provide a running version that shows the error?

king612 commented 6 years ago

No, I'm sorry, I work on a closed system. I don't know of an easy way to set up a plunkr or whatever with the Angular framework. I will post on the vega github and see if I get any suggestions.

It would be very unfortunate if we can't run vega-lite inside an Angular app. Huge base of Angular apps out there...

domoritz commented 6 years ago

We can definitely run Vega-Lite in Angular. I don't think this problem is related to Vega-Embed and so I will close this for now. Let me know if you find a solution.

king612 commented 6 years ago

OK, maybe an issue with my spec. I'll keep working on it.

Meanwhile, when you say "We can definitely run Vega-Lite in Angular..." you do mean in Angular 4/5, right? That is, from TypeScript. Or do you mean it runs fine with AngularJS (1.x). If the former, could you please provide or point me to a sample of how to run Vega-Embed from within TypeScript? I have not found an example of that anywhere. The types do not seem to be exported / imported correctly from the raw ...min.js file, for example only the vega.Warn enum shows up (other values are not recognized), etc. Any help appreciated. Thank you.

domoritz commented 6 years ago

We use Vega-Lite in Voyager (typescript, react) and the Vega-Lite examples on our website. You can check the source code.

king612 commented 6 years ago

I believe I have actually isolated it down to a vega-embed issue, and the logger error message is just a misleading downstream error. Using straight vega and vega-lite in my Angular 5 app (TypeScript) as you suggested looking at your example harness, the exact same spec that produced the errors above renders just fine. Digging around in the Chrome tools debugger seems to indicate some issue with strictness checking when TypeScript generates the packaged code. This appears to happen upstream of the logger error. I think that's just a downstream symptom when things are blown during the init/startup routines in embed.

I am using angular-cli 5.2.7 and typescript 2.6.2, although the compiler warns that it should be <2.5.0 (I have to have 2.6.x for something else), I haven't had any issues until now. But I might be screwing myself with version incompatibilities. In any event, in Chrome debug, I did see an error in the 'generator' function in the call stack whose arguments show as:

"Exception: TypeError: 'caller, 'callee', and 'arguments' properties may not be accessed in strict mode functions or the arguments object"

This may just be a debugger inspection error, but googling around found posts about strictness checking and 'use strict' being generated into third part libraries, etc. Just a heads up, I only see it with embed.

domoritz commented 6 years ago

This still sounds like an angular problem to me. You don't use typescript anymore when you import vega-embed as we have compiled a bundle.

I wish I could help better.

SStembridge commented 5 years ago

Is 'vega-lite' an html element on your page? When you call vegaEmbed('vega-lite', this.vlHelloWorld, {mode: 'vega-lite'}); the first parameter should be a DOM element or a CSS selector.

I was running into this error message and it turned out I had a typo in the first parameter; I had forgotten the # part of the css selector: Changing vegaEmbed('elementId',spec); to vegaEmbed('#elementId',spec); where the part of the html I had wanted to place my chart looked something like <div id="elementId"></div> fixed my problem.

Then I made a change that produced another problem: the div was inside an *ngIf that only evaluated to true right before I called vegaEmbed. This resulted in a situation where Angular hadn't updated the view by the time vegaEmbed was called so the element didn't exist and got evaluated to null. I fixed that by adding a ChangeDetectorRef to the component and calling detectChanges() on it to make sure the view updates before calling vegaEmbed.

For anyone else running into this error, double check that you're calling vegaEmbed() properly: https://github.com/vega/vega-embed#embed and that the container element you want to embed the chart in is actually present when you call it.

king612 commented 5 years ago

Yes, I've had this problem too, many times, on the view initialization of a complex page with many components. It can also happen on tab controls, which don't actually render a given tab's contents until the tab is selected.

If it's just an initialization problem (vs an ngif issue), you can also take advantage of the angular lifecycle hooks and implement the AfterViewInit interface with an ngAfterViewInit() method. Putting vega related stuff there ensures the all the view elements have been constructed and are present when vega tries to render the chart.

However, as you discovered, the ngIf= conditional is the worst case. Been bitten by that one many times too. In that case, yes, you have to manually register to get notification during change detection to be sure the element is finally present. Note however that in Angular, you can embed a component (e.g., a chart component) that references a parent tag higher up in the hierarchy. So sometimes I'll put the element I'm hanging the chart off of just above the component actually rendering it. Just embed your chart component in a

tag with the ID you're looking for that is unconditionally rendered. That way it's always there, and the chart renders right there where you want it. And until the chart fires, the div anchor tag is just an empty div, which doesn't disturb the layout.

John K.

On Sat, Nov 10, 2018 at 12:33 AM SStembridge notifications@github.com wrote:

Is 'vega-lite' an html element on your page? When you call vegaEmbed('vega-lite', this.vlHelloWorld, {mode: 'vega-lite'}); the first parameter should be a DOM element or a CSS selector.

I was running into this error message and it turned out I had a typo in the first parameter; I had forgotten the # part of the css selector: Changing vegaEmbed('elementId',spec); to vegaEmbed('#elementId',spec); where the part of the html I had wanted to place my chart looked something like

fixed my problem.

Then I made a change that produced another problem: the div was inside an *ngIf that only evaluated to true right before I called vegaEmbed. This resulted in a situation where Angular hadn't updated the view by the time vegaEmbed was called so the element didn't exist and got evaluated to null. I fixed that by adding a ChangeDetectorRef https://angular.io/api/core/ChangeDetectorRef to the component and calling detectChanges() on it to make sure the view updates before calling vegaEmbed.

For anyone else running into this error, double check that you're calling vegaEmbed() properly: https://github.com/vega/vega-embed#embed and that the container element you want to embed the chart in is actually present when you call it.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/vega/vega-embed/issues/64#issuecomment-437560055, or mute the thread https://github.com/notifications/unsubscribe-auth/AFYx0PZZhVaZWQ3_Xj62GokPmjuJWlrGks5utmUygaJpZM4THhc0 .