ng-switch 什么时候完成渲染? [英] When has ng-switch finished rendering?

查看:23
本文介绍了ng-switch 什么时候完成渲染?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 ui-router 并尝试实例化一个需要id 指定的 DOM 元素作为参数.此 DOM 元素位于

中,我想在保证元素存在时调用小部件构造函数.

<div ng-switch-when="map"><div id="地图"></div>

来自 ui-router 生命周期,我知道我应该挂入 $viewContentLoaded.但是,这不起作用 - ng-switch 中的 DOM 元素不是在那个时候创建​​的:

app.config(['$stateProvider', function ($stateProvider) {$stateProvider.state('/', {url: '/', templateUrl: 'index.html'}).state('map', {url: 'map', templateUrl: 'map.html', 控制器: 'MapCtrl'})}]);app.controller('MapCtrl', ['$rootScope', '$scope', '$state', function MapCtrl($rootScope, $scope, $state) {$scope.state = $state.current.name;//将状态暴露给模板,以便我们可以进行 ng-switch.显然没有更好的方法:https://github.com/angular-ui/ui-router/issues/1482$scope.$on('$viewContentLoaded', function mapContentLoaded(event, viewConfig) {var mapElement = document.getElementById('map');console.log('正在尝试将地图创建到', mapElement);var map = new google.maps.Map(mapElement);//<-- 但 mapElement 将为空!});}]);

有效的是在控制器中使用 50 毫秒的 setTimeout(),这很脆弱,但到那时 DOM 元素已创建.或者,我可以设置一个间隔,检查 map DOM 元素是否存在,并在找到时清除该间隔.

确定 ng-switch 何时呈现其 DOM 的正确方法是什么?这没有记录.

这是 Plunkr.

解决方案

我认为您落入了许多有经验的前端开发人员在使用 Angular 时落入的陷阱.在大多数其他 JS 库中,我们在创建 DOM 后对其进行修改,然后向其添加功能.但是,在 Angular 中,功能是在 HTML 中定义的.功能和交互性是通过使用指令创建的.

在 jQuery 中,这样的事情很好:

点击这里做事

<script type="text/javascript">$(函数(){$('#foobar').on('click', function () {someService.doStuff();});});

在 Angular 中,类似下面的内容更符合地道:

点击这里做事

<script type="text/javascript">app.controller('Main', ['$scope', 'someService', function ($scope, someService) {$scope.doStuff = 函数 () {someService.doStuff();}}]);

至于您的 GoogleMap 指令,这是迄今为止实现它的最简单方法.尽管这是非常基本的并且可能无法完成您需要的所有操作.

app.directive('googleMap', [function() {返回 {链接:函数(元素){新的 google.maps.Map(element);}}}]);

您的map.html:

<div ng-switch-when="map"><div google-map id="map"></div>

然而,正如您所提到的,每次点击控制器时,这都会重新创建 Google 地图.一种解决方法是保存元素和 Map api 并在后续调用中替换它:

app.directive('googleMap', [function () {var googleMapElement,谷歌地图API;返回 {链接:函数(元素){如果 (!googleMapElement || !googleMapAPI) {googleMapAPI = 新的 google.maps.Map(element);googleMapElement = 元素;}别的 {element.replaceWith(googleMapElement);}}}}]);

I'm using ui-router and trying to instantiate a widget that takes as a parameter a DOM element specified by id. This DOM element is in a <div ng-switch> and I want to call the widget constructor when the element is guaranteed to exist.

<div ng-switch on="state">
  <div ng-switch-when="map">
    <div id="map"></div>
  </div>
</div>

From the ui-router lifecycle, I understand that I should hook into $viewContentLoaded. This, however, doesn't work - the DOM element within the ng-switch isn't created at that point:

app.config(['$stateProvider', function ($stateProvider) {
  $stateProvider
    .state('/', {url: '/', templateUrl: 'index.html'})
    .state('map', {url: 'map', templateUrl: 'map.html', controller: 'MapCtrl'})
}]);

app.controller('MapCtrl', ['$rootScope', '$scope', '$state', function MapCtrl($rootScope, $scope, $state) {
  $scope.state = $state.current.name;  // expose the state to the template so we can ng-switch. Apparently there's no better way: https://github.com/angular-ui/ui-router/issues/1482

  $scope.$on('$viewContentLoaded', function mapContentLoaded(event, viewConfig) {
    var mapElement = document.getElementById('map');
    console.log('Attempting to create map into', mapElement);
    var map = new google.maps.Map(mapElement);  // <-- but mapElement will be null!
  });
}]);

What does work is using a setTimeout() of 50ms in the controller, which is brittle, but by that time the DOM element is created. Alternatively, I can set an interval, check for the presence of the map DOM element, and clear the interval when it's found.

What is the proper way of figuring out when an ng-switch has rendered its DOM? This isn't documented.

Here's the Plunkr.

解决方案

I think you're falling in the trap that many experienced front-end developers fall in to when using Angular. In most of other JS libraries we modify the DOM after it's been created and then add functionality to it. However, in Angular the functionality is defined in the HTML. Functionality and interactivity is created by using directives.

In jQuery something like this is fine:

<div id="foobar">
    Click here to do stuff
</div>

<script type="text/javascript">
    $(function () {
        $('#foobar').on('click', function () {
            someService.doStuff();
        });
    });
</script>

Whereas in Angular something like the below is more idiomatic:

<div id="foobar" ng-controller="Main" ng-click="doStuff()">
    Click here to do stuff
</div>

<script type="text/javascript">
    app.controller('Main', ['$scope', 'somerService', function ($scope, someService) {
        $scope.doStuff = function () {
            someService.doStuff();
        }
    }]);
</script>

As for your GoogleMap directive this is by far the simplest way to accomplish it. Albeit this is incredibly basic and may not do everything you need it to.

app.directive('googleMap', [function() {
    return {
      link: function(element) {
        new google.maps.Map(element);
      }
    }
  }
]);

Your map.html:

<div ng-switch on="state">
  <div ng-switch-when="map">
    <div google-map id="map"></div>
  </div>
</div>

As you mentioned however, this would recreate the Google map every time that controller is hit. One way around that is to save off the element and Map api and replacing it on subsequent calls:

app.directive('googleMap', [function () {
    var googleMapElement,
            googleMapAPI;
    return {
        link: function (element) {
            if (!googleMapElement || !googleMapAPI) {
                googleMapAPI = new google.maps.Map(element);
                googleMapElement = element;
            }
            else {
                element.replaceWith(googleMapElement);
            }

        }
    }
}]);

这篇关于ng-switch 什么时候完成渲染?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆