ng-if在AngularJS中$scope var改变时不更新

yduiuuwa  于 2023-05-12  发布在  Angular
关注(0)|答案(4)|浏览(197)

在我看来,我有这个:

<div class="tab-loading-container" ng-if="mapStatus.loading =='true'">
    <div class="tab-loading">Loading map</div>
</div>

在我的控制器中,我有:

$scope.mapStatus = {};

然后是各种函数,当满足某些标准时,例如离线等,这些函数更新ng-if使用的范围变量(例如:

function enableMap () {
    $scope.mapStatus.loading = false;
}

我的问题是,尽管scope var被正确地更改了(用好的'ol console.log和angular chrome扩展确认了),但视图中的ng-if从未更新/添加/删除以显示/删除div。
我试过使用$apply(虽然我对它的理解不是很好),例如:

function enableMap () {
    $scope.$apply(function() {
        $scope.mapStatus.loading = false;
    });
}

但这会引发错误,例如Error: [$rootScope:inprog] $apply already in progress
我觉得我错过了一些明显的东西:(
更多代码请访问:

angular.module('app.case.controller', [])
.controller('CaseController', function($rootScope, $scope, $state, $stateParams, $filter, casesFactory, $ionicActionSheet, $ionicModal, $ionicTabsDelegate, $ionicLoading, ConnectivityMonitor) {

/// Other non related code

// location map - refactor into a factory
    $scope.mapStatus = {};

    function initMap () {
        var pos = { 'lat':  52.6136149, 'lng': -1.1936672 };

        var latLng = new google.maps.LatLng(pos.lat, pos.lng);

        var mapOptions = {
            center: latLng,
            zoom: 15,
            mapTypeId: google.maps.MapTypeId.ROADMAP,
            fullscreenControl: false,
            mapTypeControl: false
        };

        $scope.map = new google.maps.Map(document.getElementById('map'), mapOptions);

        google.maps.event.trigger(map, 'resize');

        //Wait until the map is loaded
        google.maps.event.addListenerOnce($scope.map, 'idle', function () {

            enableMap();

            console.log('map loaded');

            var marker = new google.maps.Marker({
                map: $scope.map,
                animation: google.maps.Animation.DROP,
                position: latLng
            });

            google.maps.event.trigger(map, 'resize'); 

            $scope.map.setCenter(latLng);

        });
    }

    function loadGoogleMaps () {    
        $scope.mapStatus.loading = true;

        // This function will be called once the SDK has been loaded
        window.mapInit = function(){
            initMap();
        };

        // Create a script element to insert into the page
        var script = document.createElement('script');
        script.type = 'text/javascript';
        script.id = 'googleMaps';
        script.src = 'https://maps.googleapis.com/maps/api/js?key=XXX&callback=mapInit';

        document.body.appendChild(script);
    }

    function enableMap () {
        $scope.mapStatus.loading = false;
        $scope.mapStatus.offline = false;
    }

    function disableMap () {
        $scope.mapStatus.offline = true;
    }

    function checkLoaded () {
        if (typeof google == 'undefined"' || typeof google.maps == 'undefined') {
            loadGoogleMaps();
        } else {
            enableMap();
        }       
    }

    function addConnectivityListeners () {

        if (ionic.Platform.isWebView()) {

            // Check if the map is already loaded when the user comes online, if not, load it
            $rootScope.$on('$cordovaNetwork:online', function(event, networkState) {
                checkLoaded();
            });

            // Disable the map when the user goes offline
            $rootScope.$on('$cordovaNetwork:offline', function(event, networkState) {
                disableMap();
            });

        } else {

            //Same as above but for when we are not running on a device
            window.addEventListener("online", function(e) {
                checkLoaded();
            }, false);    

            window.addEventListener("offline", function(e) {
                disableMap();
            }, false);  
        }
    }

    function showMap () {

        console.log('showMap() called');

        if (typeof google == 'undefined' || typeof google.maps == 'undefined') {

            console.warn("Google Maps SDK needs to be loaded");

            disableMap();

            if (ConnectivityMonitor.isOnline()){
                loadGoogleMaps();
            }
        }
        else {
            if (ConnectivityMonitor.isOnline()){
                initMap();
                enableMap();
            } else {
                disableMap();
            }
        }

        addConnectivityListeners();
    }

    $scope.initMap = function () {
        showMap();
    };

为了确认范围变量正在更改,这里是AngularJS chrome扩展的屏幕截图:

nle07wnf

nle07wnf1#

我不确定这是否能解决您的问题,但在您深入研究之前,我建议您摆脱对$scope的引用并使用controllerAs。我见过很多示例,其中对属性/方法的引用直接添加到$scope失败,没有特别的原因。具体来说,我建议您:

  • 删除注入了$scope的地方,
  • var ctrl=this添加到控制器中的构造函数代码中,
  • 将控制器中所有对$scope的引用更改为ctrl,
  • 将controllerAs vm添加到加载控制器的位置,
  • 将视图中所有对控制器属性的引用改为前缀为vm。

你可能会很幸运,这可能只是解决你的问题,但无论哪种方式,这仍然是一个更好的方式与控制器。(如果你使用的是Angular 1.5+,我真的建议你把它重构为一个组件,在你走得太远之前。

5rgfhyps

5rgfhyps2#

我已经改变了它,所以它只是一个布尔值,而不是将其与字符串进行比较。您是否曾经将$scope.mapStatus.loading设置为true?否则,它永远不会显示,因为它永远是假的。

var myApp = angular.module('myApp', []);

function MyCtrl($scope) {
  $scope.mapStatus = {};

  $scope.hideMe = function() {
    $scope.mapStatus.loading = false;
  }

  $scope.showMe = function() {
    $scope.mapStatus.loading = true;
  }
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp">
  <div ng-controller="MyCtrl">
    <div class="tab-loading-container" ng-if="mapStatus.loading">
      <div class="tab-loading">Loading map</div>
    </div>
    <button ng-click="hideMe()">Hide Me</button>
    <button ng-click="showMe()">Show Me</button>
  </div>
</div>
pb3s4cty

pb3s4cty3#

(我发布这个答案是为了防止有人在使用angular v2+时遇到这个问题)
如果ngIf指令引用的表达式被来自Angular 区域外部的(异步)调用更新,则可能发生此问题。这不会导致angular中的更改检测,因此直到下一次更改检测发生时,您的视图才会更新。您可以通过以下链接了解有关区域和更改检测的更多信息:zoneschange detection
我在将google sign in集成到我的组件中时遇到了这个问题。signInChangeListener在用户登录或退出时由第三方google库调用:

export class GoogleLoginService {
   signedIn: boolean = false;
   ...
   signInChangeListener(isSignedIn) {
       this.signedIn = isSignedIn;
   }
}

在我的HTML中,我有:

<div *ngIf="signedIn"> ... </div>

我不得不更改代码,以便angular检测到更改:

import { Injectable, NgZone } from '@angular/core';

export class GoogleLoginService {
   signedIn: boolean = false;

   constructor(private ngZone: NgZone) { }
   ...
   signInChangeListener(isSignedIn) {
      // Run the value change inside angular 
      this.ngZone.run(() => {
         this.signedIn = isSignedIn;
      });
   }
}
hc8w905p

hc8w905p4#

如果你使用John Papa的Controller As模式和vm,请确保你在模板中使用的是控制器的名称,而不是vm:

controller: 'featureController',
controllerAs: 'featureCtrl'

在Controller中使用vm.value:

const vm = this;

vm.value = true;

在模板中使用featureController.value:

<span>Here is the value: {{featureController.value}}</span>

相关问题