Trouble passing filter (viz-filter) value from Angular application to embedded web-component Tableau report

huangapple go评论67阅读模式
英文:

Trouble passing filter (viz-filter) value from Angular application to embedded web-component Tableau report

问题

I'm having trouble embedding and configuring a Tableau report inside of an Angular 15 app. What I want to do is just pass an initial filter value, and then show the report. Here is a code sample of a report running properly in regular old HTML/JS:

这里我在嵌入和配置Tableau报告到Angular 15应用程序时遇到了问题。我想要做的是只传递一个初始筛选值,然后显示报告。以下是在常规的HTML/JS中正确运行的报告示例:

This works fine. The report loads, filtered to the proper channelGrouping. However, if I bring this into an Angular context, I cannot get the dynamic value I want to pass to viz-filter to bind. This has gotta be something silly, but I can't figure it out.

这个工作得很好。报告加载并进行了适当的channelGrouping筛选。然而,如果将其引入到Angular上下文中,我无法获取要绑定到 viz-filter 的动态值。这肯定是一些愚蠢的问题,但我想不出来。

In my Angular application, I'm including this in my index.html page (note that it's different from the referenced version in the above example):

在我的Angular应用程序中,我在index.html页面中包含了这个(注意,这与上面示例中引用的版本不同):

<script type="module" src="https://embedding.tableauusercontent.com/tableau.embedding.3.1.0.min.js"></script>

...and then this is the Angular component:

然后这是Angular组件:

import { CommonModule } from '@angular/common';
import { CUSTOM_ELEMENTS_SCHEMA, Component } from '@angular/core';

@Component({
  selector: 'app-tableau-embed',
  standalone: true,
  imports: [CommonModule],
  schemas: [CUSTOM_ELEMENTS_SCHEMA],
  template: `<tableau-viz
  id="tableau1"
  src="https://public.tableau.com/views/DigitalMarketingWebTraffic/Cockpit?:language=en-US&:display_count=n&:origin=viz_share_link">
</tableau-viz>`,
  styleUrls: [],
})
export class TableauEmbedComponent {}

This works fine.

这个工作得很好。

But as soon as I introduce viz-filter, I start to run into weird problems. For example, this works:

但是,一旦我引入 viz-filter,我开始遇到奇怪的问题。例如,这个可以工作:

import { CommonModule } from '@angular/common';
import { CUSTOM_ELEMENTS_SCHEMA, Component } from '@angular/core';

@Component({
  selector: 'app-tableau-embed',
  standalone: true,
  imports: [CommonModule],
  schemas: [CUSTOM_ELEMENTS_SCHEMA],
  template: `<tableau-viz
  id="tableau1"
  src="https://public.tableau.com/views/DigitalMarketingWebTraffic/Cockpit?:language=en-US&:display_count=n&:origin=viz_share_link">
  <viz-filter field="ga:channelGrouping" value="Direct" />
</tableau-viz>`,
  styleUrls: [],
})
export class TableauEmbedComponent {}

However, if I try to bind the value attribute to an Angular class variable, like this:

然而,如果我尝试将 value 属性绑定到一个Angular类变量,就像这样:

import { CommonModule } from '@angular/common';
import { CUSTOM_ELEMENTS_SCHEMA, Component } from '@angular/core';

@Component({
  selector: 'app-tableau-embed',
  standalone: true,
  imports: [CommonModule],
  schemas: [CUSTOM_ELEMENTS_SCHEMA],
  template: `<tableau-viz
  id="tableau1"
  src="https://public.tableau.com/views/DigitalMarketingWebTraffic/Cockpit?:language=en-US&:display_count=n&:origin=viz_share_link">
  <viz-filter field="ga:channelGrouping" [value]="channelGrouping" />
</tableau-viz>`,
  styleUrls: [],
})
export class TableauEmbedComponent {
  channelGrouping = 'Direct';
}

...it doesn't work. In the DOM inspector, what I see is literally this:

...但是它不起作用。在DOM检查器中,我看到的实际上是这样的:

Trouble passing filter (viz-filter) value from Angular application to embedded web-component Tableau report

The entire value attribute just doesn't show up. I've tried this:

整个 value 属性都没有显示出来。我尝试过这个:

<viz-filter field="user_id" [attr.value]="channelGrouping" />

...which seems like it does the right thing, in that the DOM inspector shows the value attribute, with the proper value passed along:

...看起来似乎做了正确的事情,因为DOM检查器显示了带有正确值的 value 属性:

Trouble passing filter (viz-filter) value from Angular application to embedded web-component Tableau report

...but Tableau doesn't appear to like that because the Tableau report ignores that value, which makes me think it's not really getting passed to Tableau, for whatever reason. (Again, if I hard-code that value in viz-filter, then Tableau behaves properly.)

...但是Tableau似乎不喜欢这样做,因为Tableau报告忽略了该值,这让我觉得它实际上没有传递给Tableau,不管出于什么原因。 (再次强调,如果我在 viz-filter 中硬编码该值,那么Tableau会正常工作。)

I've also tried this:

我还尝试过这个:

<viz-filter field="ga:channelGrouping" value="{{ channelGrouping }}" />

and:

和:

<viz-filter field="ga:channelGrouping" attr.value="{{ channelGrouping }}" />

...but I get the same issue where I just see <viz-filter field="ga:channelGrouping" />.

...但是我遇到了同样的问题,我只看到 <viz-filter field="ga:channelGrouping" />

And for the sake of completion, if I do this:

出于完整性的考虑,如果我这样做:

<tableau-viz
        id="tableauViz"
        src="https://public.tableau.com/views/DigitalMarketingWebTraffic/Cockpit?:language=en-US&:display_count=n&:origin=viz_share_link">
        <viz-filter field="ga:channelGrouping" [value]="channelGrouping" />
        <div [id]="channelGrouping"></div>
      </tableau-viz>
英文:

I'm having trouble embedding and configuring a Tableau report inside of an Angular 15 app. What I want to do is just pass an initial filter value, and then show the report. Here is a code sample of a report running properly in regular old HTML/JS:

&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;en&quot;&gt;
&lt;head&gt;
    &lt;script type=&quot;module&quot; src=&quot;https://public.tableau.com/javascripts/api/tableau.embedding.3.latest.js&quot;&gt;&lt;/script&gt;
&lt;/head&gt;
&lt;body&gt;

&lt;tableau-viz id=&quot;tableauViz&quot; src=&quot;https://public.tableau.com/views/DigitalMarketingWebTraffic/Cockpit?:language=en-US&amp;:display_count=n&amp;:origin=viz_share_link&quot;&gt;
    &lt;viz-filter field=&quot;ga:channelGrouping&quot; value=&quot;Social&quot; /&gt;
&lt;/tableau-viz&gt;

&lt;/body&gt;
&lt;/html&gt;

This works fine. The report loads, filtered to the proper channelGrouping. However, if I bring this into an Angular context, I cannot get the dynamic value I want to pass to viz-filter to bind. This has gotta be something silly, but I can't figure it out.

In my Angular application, I'm including this in my index.html page (note that it's different from the referenced version in the above example):

&lt;script type=&quot;module&quot;
  src=&quot;https://embedding.tableauusercontent.com/tableau.embedding.3.1.0.min.js&quot;&gt;&lt;/script&gt;

...and then this is the Angular component:

import { CommonModule } from &#39;@angular/common&#39;;
import { CUSTOM_ELEMENTS_SCHEMA, Component } from &#39;@angular/core&#39;;

@Component({
  selector: &#39;app-tableau-embed&#39;,
  standalone: true,
  imports: [CommonModule],
  schemas: [CUSTOM_ELEMENTS_SCHEMA],
  template: `&lt;tableau-viz
  id=&quot;tableau1&quot;
  src=&quot;https://public.tableau.com/views/DigitalMarketingWebTraffic/Cockpit?:language=en-US&amp;:display_count=n&amp;:origin=viz_share_link&quot;&gt;
&lt;/tableau-viz&gt;`,
  styleUrls: [],
})
export class TableauEmbedComponent {}

This works fine.

But as soon as I introduce viz-filter, I start to run into weird problems. For example, this works:

import { CommonModule } from &#39;@angular/common&#39;;
import { CUSTOM_ELEMENTS_SCHEMA, Component } from &#39;@angular/core&#39;;

@Component({
  selector: &#39;app-tableau-embed&#39;,
  standalone: true,
  imports: [CommonModule],
  schemas: [CUSTOM_ELEMENTS_SCHEMA],
  template: `&lt;tableau-viz
  id=&quot;tableau1&quot;
  src=&quot;https://public.tableau.com/views/DigitalMarketingWebTraffic/Cockpit?:language=en-US&amp;:display_count=n&amp;:origin=viz_share_link&quot;&gt;
  &lt;viz-filter field=&quot;ga:channelGrouping&quot; value=&quot;Direct&quot; /&gt;
&lt;/tableau-viz&gt;`,
  styleUrls: [],
})
export class TableauEmbedComponent {}

However, if I try to bind the value attribute to an Angular class variable, like this:

import { CommonModule } from &#39;@angular/common&#39;;
import { CUSTOM_ELEMENTS_SCHEMA, Component } from &#39;@angular/core&#39;;

@Component({
  selector: &#39;app-tableau-embed&#39;,
  standalone: true,
  imports: [CommonModule],
  schemas: [CUSTOM_ELEMENTS_SCHEMA],
  template: `&lt;tableau-viz
  id=&quot;tableau1&quot;
  src=&quot;https://public.tableau.com/views/DigitalMarketingWebTraffic/Cockpit?:language=en-US&amp;:display_count=n&amp;:origin=viz_share_link&quot;&gt;
  &lt;viz-filter field=&quot;ga:channelGrouping&quot; [value]=&quot;channelGrouping&quot; /&gt;
&lt;/tableau-viz&gt;`,
  styleUrls: [],
})
export class TableauEmbedComponent {
  channelGrouping = &#39;Direct&#39;;
}

...it doesn't work. In the DOM inspector, what I see is literally this:

Trouble passing filter (viz-filter) value from Angular application to embedded web-component Tableau report

The entire value attribute just doesn't show up. I've tried this:

  &lt;viz-filter field=&quot;user_id&quot; [attr.value]=&quot;channelGrouping&quot; /&gt;

...which seems like it does the right thing, in that the DOM inspector shows the value attribute, with the proper value passed along:

Trouble passing filter (viz-filter) value from Angular application to embedded web-component Tableau report

...but Tableau doesn't appear to like that because the Tableau report ignores that value, which makes me think it's not really getting passed to Tableau, for whatever reason. (Again, if I hard-code that value in viz-filter, then Tableau behaves properly.)

I've also tried this:

&lt;viz-filter field=&quot;ga:channelGrouping&quot; value=&quot;{{ channelGrouping }}&quot; /&gt;

and:

&lt;viz-filter field=&quot;ga:channelGrouping&quot; attr.value=&quot;{{ channelGrouping }}&quot; /&gt;

...but I get the same issue where I just see &lt;viz-filter field=&quot;ga:channelGrouping&quot; /&gt;.

And for the sake of completion, if I do this:

&lt;tableau-viz
        id=&quot;tableauViz&quot;
        src=&quot;https://public.tableau.com/views/DigitalMarketingWebTraffic/Cockpit?:language=en-US&amp;:display_count=n&amp;:origin=viz_share_link&quot;&gt;
        &lt;viz-filter field=&quot;ga:channelGrouping&quot; [value]=&quot;channelGrouping&quot; /&gt;
        &lt;div [id]=&quot;channelGrouping&quot;&gt;&lt;/div&gt;
      &lt;/tableau-viz&gt;

I see this:

Trouble passing filter (viz-filter) value from Angular application to embedded web-component Tableau report

...where the class variable channelGrouping is clearly bound to the id attribute of the div tag which is a sibling to the viz-filter tag.

Here's the start of a Stackblitz which has all the code that should be required for this to run--but of course for some reason this code is not actually working in Stackblitz.

https://stackblitz.com/edit/angular-uch2bk?file=src%2Ftableau-embed.ts

答案1

得分: 0

以下是您要翻译的代码部分:

For anybody who stumbles across this, I've figured out one approach that works. I can't say with 100% certainty that this is the "right" way to do this, though it probably is.

The issue is that Angular treats the `value` attribute on `viz-filter` differently than the `src` and `id` attributes on `tableau-viz`. In short, you can't use data binding on `value` in `viz-filter`, and so need to use `Renderer2` to grab that component's native element, and then call `setAttribute` against that. Here's the complete code of the Angular component I'm using to embed a Tableau dashboard:

import { CommonModule } from '@angular/common';
import {
  AfterViewInit,
  CUSTOM_ELEMENTS_SCHEMA,
  Component,
  ElementRef,
  HostListener,
  Input,
  OnInit,
  Renderer2,
  SimpleChanges,
  ViewChild,
  inject,
} from '@angular/core';

@Component({
  selector: 'app-tableau-embed',
  standalone: true,
  imports: [CommonModule],
  schemas: [CUSTOM_ELEMENTS_SCHEMA],
  template: `<div #wrapper>
    <tableau-viz
      [id]="vizIndex"
      [src]="url"
      width="{{ screenWidth }}"
      hide-tabs
      toolbar="hidden">
      <viz-filter #vizFilterUserId field="user_id"></viz-filter>
    </tableau-viz>
  </div>`,
  styleUrls: [],
})
export class TableauEmbedComponent implements AfterViewInit, OnInit {
  private renderer = inject(Renderer2);

  @Input() dashboardIndex = 0;
  @Input() toolbar = 'hidden';
  @Input() url = '';
  @Input() user_id = '';
  @ViewChild('wrapper') wrapperElement?: ElementRef<HTMLElement>;
  @ViewChild('vizFilterUserId', { static: false }) vizFilterUserId?: ElementRef;
  @HostListener('window:resize', ['$event'])
  onWindowResize() {
    this.calculateDashboardSize();
  }

  initialized = false;
  screenWidth: number = 0;
  vizIndex = `Tableau-Viz-${this.dashboardIndex}`;

  calculateDashboardSize = () => {
    const bufferSize = 25;
    this.screenWidth =
      this.wrapperElement?.nativeElement.offsetWidth || 0 - bufferSize;
  };

  ngOnInit(): void {
    this.calculateDashboardSize();
  }

  ngAfterViewInit(): void {
    if (this.vizFilterUserId) {
      this.renderer.setAttribute(
        this.vizFilterUserId.nativeElement,
        'value',
        this.user_id
      );
    }
  }
}
英文:

For anybody who stumbles across this, I've figured out one approach that works. I can't say with 100% certainty that this is the "right" way to do this, though it probably is.

The issue is that Angular treats the value attribute on viz-filter differently than the src and id attributes on tableau-viz. In short, you can't use data binding on value in viz-filter, and so need to use Renderer2 to grab that component's native element, and then call setAttribute against that. Here's the complete code of the Angular component I'm using to embed a Tableau dashboard:

import { CommonModule } from &#39;@angular/common&#39;;
import {
AfterViewInit,
CUSTOM_ELEMENTS_SCHEMA,
Component,
ElementRef,
HostListener,
Input,
OnInit,
Renderer2,
SimpleChanges,
ViewChild,
inject,
} from &#39;@angular/core&#39;;
@Component({
selector: &#39;app-tableau-embed&#39;,
standalone: true,
imports: [CommonModule],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
template: `&lt;div #wrapper&gt;
&lt;tableau-viz
[id]=&quot;vizIndex&quot;
[src]=&quot;url&quot;
width=&quot;{{ screenWidth }}&quot;
hide-tabs
toolbar=&quot;hidden&quot;&gt;
&lt;viz-filter #vizFilterUserId field=&quot;user_id&quot;&gt;&lt;/viz-filter&gt;
&lt;/tableau-viz&gt;
&lt;/div&gt;`,
styleUrls: [],
})
export class TableauEmbedComponent implements AfterViewInit, OnInit {
private renderer = inject(Renderer2);
@Input() dashboardIndex = 0;
@Input() toolbar = &#39;hidden&#39;;
@Input() url = &#39;&#39;;
@Input() user_id = &#39;&#39;;
@ViewChild(&#39;wrapper&#39;) wrapperElement?: ElementRef&lt;HTMLElement&gt;;
@ViewChild(&#39;vizFilterUserId&#39;, { static: false }) vizFilterUserId?: ElementRef;
@HostListener(&#39;window:resize&#39;, [&#39;$event&#39;])
onWindowResize() {
this.calculateDashboardSize();
}
initialized = false;
screenWidth: number = 0;
vizIndex = `Tableau-Viz-${this.dashboardIndex}`;
calculateDashboardSize = () =&gt; {
const bufferSize = 25;
this.screenWidth =
this.wrapperElement?.nativeElement.offsetWidth || 0 - bufferSize;
};
ngOnInit(): void {
this.calculateDashboardSize();
}
ngAfterViewInit(): void {
if (this.vizFilterUserId) {
this.renderer.setAttribute(
this.vizFilterUserId.nativeElement,
&#39;value&#39;,
this.user_id
);
}
}
}

huangapple
  • 本文由 发表于 2023年7月18日 06:19:33
  • 转载请务必保留本文链接:https://go.coder-hub.com/76708425.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定