angular 路由解析 - 等待定义值

angular route resolve - wait on value to be defined

我有条件地为 load/unload javascript 和 css 写了一个包装器。它在路由解析部分被称为:

resolve: {
    factory: function (Res) {
        controllersAndServices(Res, {styles: 'estilos/check_insurance.css'})
    }
}

它通常很有魅力。问题是,一些库,比如 Plotly 推迟创建它们的主变量,所以库在可用之前加载。结果,我收到 Plotly 未在我的控制器中定义的错误,然后它们消失了。 肯定 当我到达控制台时,Plotly 正在愉快地等着我。

我确实意识到我的自定义加载器可能会在更多的库中发生这种情况,但令人高兴的是,大多数库都太小而不会出现这个问题。 plotly 很大,可能需要数百甚至数千毫秒才能设置。

所以我需要等待 Plotly 在我的 resolve 中以某种方式被定义。你是怎么做到的?

图书馆:

res_service.js

angular.module('app').service('Res', ['$rootScope', function ($rootScope) {
    var scope = $rootScope
    scope._scripts = scope._scripts || []
    scope._styles = scope._styles || []
    scope._rawScripts = scope._rawScripts || []
    scope._rawStyles = scope._rawStyles || []

    return {
        style: function (inp) {
            var hrefs = []
            if (typeof inp === 'string') {
                hrefs.push(inp)
            } else {
                hrefs = inp
            }

            scope._styles = []
            for (var i in hrefs) {
                console.log('styling page with ' + hrefs[i])
                var style = document.createElement('link')
                if (!/^https?\:\/\//.test(hrefs[i])) {
                    style.type = 'text/css'
                }
                style.href = hrefs[i]
                style.rel = 'stylesheet'

                if (scope._rawStyles === undefined) {
                    scope._rawStyles = []
                }
                scope._rawStyles.push([hrefs[i], style])
                scope._styles.push(document.head.appendChild(style))

                scope.$on('$destroy', this.clean_styles)
            }
        },

        clean_styles: function () {
            var removables = []
            for (var key in scope._rawStyles) {
                console.log('deleting style ' + scope._rawStyles[key][0])
                scope._styles[key].parentNode.removeChild(scope._rawStyles[key][1])
                removables.push(key)
            }

            scope._styles = scope._styles.filter(function (v) { return (removables.indexOf(v) !== -1)? true: false })
            scope._rawStyles = scope._rawStyles.filter(function (v) { return (removables.indexOf(v) !== -1)? true: false })
        },

        script: function (inp) {
            var hrefs = []
            if (typeof inp === 'string') {
                hrefs.push(inp)
            } else {
                hrefs = inp
            }

            scope._scripts = []
            for (var i in hrefs) {
                console.log('loading javascript: ' + hrefs[i])
                var script = document.createElement('script')
                if (!/^https?\:\/\//.test(hrefs[i])) {
                    script.type = 'text/javascript'
                }
                script.src = hrefs[i]

                if (scope._rawScripts === undefined) {
                    scope._rawScripts = []
                }
                scope._rawScripts.push([hrefs[i], script])
                scope._scripts.push(document.head.appendChild(script))

                scope.$on('$destroy', this.clean_scripts)
            }
        },

        clean_scripts: function () {
            var removables = []
            for (var key in scope._rawScripts) {
                console.log('deleting script ' + scope._rawScripts[key][0])
                scope._scripts[key].parentNode.removeChild(scope._rawScripts[key][1])
                removables.push(key)
            }

            scope._scripts = scope._scripts.filter(function (v) { return (removables.indexOf(v) !== -1)? true: false })
            scope._rawScripts = scope._rawScripts.filter(function (v) { return (removables.indexOf(v) !== -1)? true: false })
        }

    }
}])

中断路由用法示例:

route.js

...
                when('/', {
                    templateUrl: 'hipermídia/check_insurance.template.html',
                    controller: 'pedidos_controller',
                    resolve: {
                        factory: function (Res) {
                            controllersAndServices(Res, {scripts: 'https://cdn.plot.ly/plotly-latest.min.js'})
                        }
                    }
                }).

此时,如果您在控制器中使用 plotly,例如:

var data = [
  {
    x: ['giraffes', 'orangutans', 'monkeys'],
    y: [20, 14, 23],
    type: 'bar'
  }
];

Plotly.newPlot('myDivID', data);

您可能会得到类似 ReferenceError: Plotly is not defined 的结果。 如果你将它移开,通过同步调用,可能是 setTimeout,甚至只是 angular 的文档准备就绪,看到正确图表的可能性就会增加。

有点hacky,但我会loop/test如果Plotly var存在于根路由中,每条需要库的路由都是其子路由(解析应用于子路由如果他们也注入 属性)。

类似下面的内容将在根路由中得到解决:

resolve: {
    plotly: function () {
        const resolvePlotly = function () {
          while (typeOf Plotly) === 'undefined') {
            return setTimeout(function () { resolvePlotly() }, 150)
          }
          return Plotly
        }

        return resolvePlotly()
    }
}

我会将已解析的注入添加到该路由,并将其传递给子路由,这样依赖项仍会等待 Plotly 对象在 运行 任何依赖控制器之前定义.

您还可以编写一个工厂包装 Plotly 对象,returns 它可用时 inject/use 它而不是直接访问 Plotly.