【问题标题】:When has ng-switch finished rendering?ng-switch 什么时候完成渲染?
【发布时间】:2014-12-22 03:59:26
【问题描述】:

我正在使用ui-router 并尝试实例化一个以id 指定的DOM 元素作为参数的小部件。此 DOM 元素位于 <div ng-switch> 中,我想在保证元素存在时调用小部件构造函数。

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

ui-router lifecycle,我明白我应该挂钩$viewContentLoaded。但是,这不起作用 - ng-switch 中的 DOM 元素此时并未创建:

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!
  });
}]);

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

确定ng-switch 何时呈现其DOM 的正确方法是什么?这个isn't documented

这是Plunkr

【问题讨论】:

  • 您正在通过同时使用 dom 方法和 angular 方法来混合隐喻/域,这对于 angular 来说效果不佳。使用指令或模板来操作 mapElement 而不是 dom 方法。
  • 你打算用mapElement做什么?不管是什么,@dandavis 都是正确的,你通常只想在指令中进行 DOM 操作。
  • @EstebanFelix:我想实例化一个谷歌地图。刚刚更新了问题。我应该怎么做?使用 ui-router 状态而不是 ng-switch?
  • 幸运的是,有很多谷歌地图组件准备好去角,搜索一个
  • @dandavis:我知道。最受欢迎的两个无缘无故地依赖 jQuery,这对我的客户来说是不可接受的。我已经为此提交了 GitHub 问题,例如here.

标签: javascript html angularjs angular-ui-router ng-switch


【解决方案1】:

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

在 jQuery 中可以这样:

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

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

在 Angular 中类似下面的内容更为惯用:

<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>

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

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

你的map.html

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

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

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);
            }

        }
    }
}]);

【讨论】:

  • 感谢您的回答!必须再读一遍jQuery -> Angular SO。每次路由器登陆该页面时,使用指令是否会导致重新创建地图?这是我试图避免的事情。
  • 如果我在写这篇回复之前说我没有读过这句话,那我就是个骗子。如果您使用 jQuery 很长时间,这绝对是您需要重新学习的肌肉。不幸的是,每次激活开关时它都会重新创建它。
  • 我设法避免重新创建,看来,通过在运行 new google.maps.Map(...) 后将 mapDomElement = document.getElementById('map') 存储到 map.domElements .value 中,然后运行 ​​mapDomElement.parentNode.replaceChild(map.domElements, mapDomElement); 如果设置了该值,而不是调用 Google Maps 构造函数。
  • 唉,看来ng-switch isn't the way to go when using ui-router。相反,应该使用嵌套状态和视图。
  • @DanDascalescu 啊,你打败了我=P。是的,从长远来看,这绝对是一个更好的方法。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-08-02
  • 2020-06-19
  • 2023-02-20
  • 1970-01-01
  • 1970-01-01
  • 2020-08-14
相关资源
最近更新 更多