Angular 14中使用tableau-viz Web组件嵌入Tableau失败问题
Angular 14嵌入Tableau Cloud内容的问题解决方案
一、解决tableau-viz被识别为未知元素的问题
Angular默认会将自定义Web组件标记为未知元素,通过以下两步修复:
- 添加自定义元素Schema
在组件所属模块(如app.module.ts)中导入并声明CUSTOM_ELEMENTS_SCHEMA,告知Angular允许使用自定义元素:
import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { AppComponent } from './app.component'; @NgModule({ declarations: [AppComponent], imports: [BrowserModule], providers: [], bootstrap: [AppComponent], schemas: [CUSTOM_ELEMENTS_SCHEMA] // 新增配置 }) export class AppModule { }
如果使用独立组件,直接在组件装饰器中添加schemas:
import { Component, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'], schemas: [CUSTOM_ELEMENTS_SCHEMA] }) export class AppComponent { /* ... */ }
- 确保Tableau嵌入脚本加载时机
直接在index.html引入脚本可能存在加载延迟问题,建议在组件中动态加载脚本,保证Web组件注册完成后再渲染tableau-viz标签:
import { Component, Renderer2, Inject, OnInit } from '@angular/core'; import { DOCUMENT } from '@angular/common'; @Component({ selector: 'app-root', templateUrl: './app.component.html' }) export class AppComponent implements OnInit { constructor( private renderer: Renderer2, @Inject(DOCUMENT) private document: Document ) {} ngOnInit(): void { const script = this.renderer.createElement('script'); script.type = 'module'; script.src = 'https://10az.online.tableau.com/javascripts/api/tableau.embedding.3.latest.min.js'; this.renderer.appendChild(this.document.body, script); } }
二、解决JavaScript API嵌入不触发登录弹窗的问题
针对JS API嵌入无登录弹窗的情况,从以下几点排查修复:
- 确保Tableau脚本加载完成后初始化Viz
避免因脚本未加载完成导致tableau对象未定义,调整初始化逻辑:
import { Component, ViewChild, ElementRef, OnInit, Inject } from '@angular/core'; import { DOCUMENT } from '@angular/common'; @Component({ selector: 'app-root', templateUrl: './app.component.html' }) export class AppComponent implements OnInit { @ViewChild("vizContainer") containerDiv!: ElementRef; private viz?: tableau.Viz; constructor(@Inject(DOCUMENT) private document: Document) {} ngOnInit(): void { this.loadTableauScript().then(() => this.initTableau()); } private loadTableauScript(): Promise<void> { return new Promise((resolve) => { if (typeof tableau !== 'undefined') { resolve(); return; } const script = this.document.createElement('script'); script.src = 'https://10az.online.tableau.com/javascripts/api/tableau-2.min.js'; // JS API专用脚本 script.onload = () => resolve(); this.document.body.appendChild(script); }); } private initTableau(): void { const vizUrl = "https://10az.online.tableau.com/t/company/views/viewname?:embed=yes&:toolbar=no"; const options = { hideTabs: true, authenticationPromptEnabled: true, // 显式开启认证弹窗 onFirstInteractive: () => { console.log("onFirstInteractive"); }, onFirstVizSizeKnown: () => { console.log("onFirstVizSizeKnown"); } }; this.viz = new tableau.Viz( this.containerDiv.nativeElement, vizUrl, options ); } }
注意:JS API和Web组件的脚本不通用,JS API需引入tableau-2.min.js而非嵌入组件的脚本。
- 处理Angular安全策略拦截
Angular的DomSanitizer可能拦截外部资源URL,需将Viz URL标记为安全资源:
import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser'; // 组件构造器注入DomSanitizer constructor( @Inject(DOCUMENT) private document: Document, private sanitizer: DomSanitizer ) {} // 在initTableau中修改URL: const vizUrl: SafeResourceUrl = this.sanitizer.bypassSecurityTrustResourceUrl( "https://10az.online.tableau.com/t/company/views/viewname?:embed=yes&:toolbar=no" );
- 检查Tableau Cloud站点配置
确保Tableau Cloud站点允许外部嵌入:
- 登录Tableau Cloud进入站点设置
- 确认"嵌入设置"中允许你的Angular应用域名嵌入内容
内容的提问来源于stack exchange,提问作者codemonger
相关产品推荐
相关产品推荐

