Quantcast
Channel: 天空的垃圾場
Viewing all articles
Browse latest Browse all 144

AngularJS - AngularJS 與 UI-Bootstrap Scope的陷阱

$
0
0

這幾天,遇雷的狀況,都已經快要變成索爾了…而今天要談的這個問題,其實算是JS加上AngularJS的基本功…牽涉的範圍還滿廣泛的…從UI-Bootstrap這個Directive開始..到AngularJS Scope的範圍,一直到JavaScript的原型繼承…

而這篇的整個概念可以看原文這裡,對岸的高手,也有幫忙翻譯成簡體中文,所以有興趣的可以先看一下上面這些資訊( 沒時間看的朋友也沒關係,可以先聽小弟講完,再回頭看… );而以下的敘述,會依據上面的理論來開始解釋小弟遇到的問題…

問題

首先,我們還是要先來看一下問題…

大家可以從這邊看到原始碼…另外,我也貼一份在Blog…

HTML

<!doctype html>
<html ng-app="plunker">
  <head>
    <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.10/angular.js"></script>
    <script src="//angular-ui.github.io/bootstrap/ui-bootstrap-tpls-0.11.0.js"></script>
    <script src="script.js"></script>
    <link href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css" rel="stylesheet">
  </head>
  <body>

<div ng-controller="ModalDemoCtrl">
    <script type="text/ng-template" id="myModalContent.html">
        <div class="modal-header">
            <h3 class="modal-title">I'm a modal!</h3>
        </div>
        <div class="modal-body">
            <ul>
                <li ng-repeat="item in items">
                    <a ng-click="selected.item = item">{{ item }}</a>
                </li>
            </ul>
            Selected: <b>{{ selected.item }}</b>
        </div>
        <input type="text" ng-model="testText"  />
        <div class="modal-footer">
            <button class="btn btn-primary" ng-click="ok()">OK</button>
            <button class="btn btn-warning" ng-click="cancel()">Cancel</button>
        </div>
    </script>

    <button class="btn btn-default" ng-click="open()">Open me!</button>
    <div ng-show="selected">Selection from a modal: {{ selected }}</div>
</div>
  </body>
</html>

JS

angular.module('plunker', ['ui.bootstrap']);
var ModalDemoCtrl = function ($scope, $modal, $log) {

  $scope.items = ['item1', 'item2', 'item3'];

  $scope.open = function (size) {

    var modalInstance = $modal.open({
      templateUrl: 'myModalContent.html',
      controller: ModalInstanceCtrl,
      size: size,
      resolve: {
        items: function () {
          return $scope.items;
        }
      }
    });

    modalInstance.result.then(function (selectedItem) {
      $scope.selected = selectedItem;
    }, function () {
      $log.info('Modal dismissed at: ' + new Date());
    });
  };
};

// Please note that $modalInstance represents a modal window (instance) dependency.
// It is not the same as the $modal service used above.

var ModalInstanceCtrl = function ($scope, $modalInstance, items) {

  $scope.items = items;
  $scope.selected = {
    item: $scope.items[0]
  };

  $scope.ok = function () {
    alert($scope.testTest);
    $modalInstance.close($scope.selected.item);
  };

  $scope.cancel = function () {
    $modalInstance.dismiss('cancel');
  };
};

好,稍微解釋一下這個問題,這個問題主要是使用UI-Bootstrap Modal的時候,如果我們再彈跳視窗的地方,加上一個Textbox,並且用ng-model ( 原始碼上是Bind到testText )來做Bind;最後當我們按下ok按鈕的時候,會用alert($scope.testText)來顯示值…

但實際上,大家玩過後可以發現,是找不到這個值的…而且這個值為定義…

解法

這個解法其實很簡單,我們只要把Text的ng-model改成繫結$parent.testText就可以了…所以會長的如下這樣:

把原本繫結testText改成$parent.testText…

<input type="text" ng-model="$parent.testText"  />

是的,這樣alert就可以順利彈跳出來值…

此外,你也可以改成這樣…變成繫結oo.testText

<input type="text" ng-model="oo.testText"  />

但這時候,JavaScript那邊也要跟調整…我們在一開始的時候設定oo為物件,並且alert改為alert($scope.oo.testText)。

var ModalInstanceCtrl = function ($scope, $modalInstance, items) {
  
  $scope.oo = {};
  $scope.items = items;
  $scope.selected = {
    item: $scope.items[0]
  };

  $scope.ok = function () {
    alert($scope.oo.testText);
    $modalInstance.close($scope.selected.item);
  };

  $scope.cancel = function () {
    $modalInstance.dismiss('cancel');
  };
};

是的,以下兩種方法都可以順利解決這個問題…但是大家一定會覺得很奇怪和納悶…為什麼這樣就可以??

解釋

首先,我們回去思索一下問題。

小弟我使用UI-Bootstrap的Modal,並且定義了這個Modal獨立的Controller,但為什麼這個Modal畫面上的ng-model,在Modal這個Controller上讀不到…反之…加了$Parent或是使用oo.這種寫法就可以讀的到!?

其實原理就是一開始給大家看的那個網址( 如果沒看的朋友也沒關係,可以繼續看下去 );小弟引用了一下原文的一張圖,其實原理就是這張圖上…

image

我們使用的UI-Bootstrap其實是用AngularJS的Directive寫的,這點我相信大家都沒啥問題…而UI-Bootstrap在設定Directive有使用到Transclude ( Transclude 是替換內容的功能 ),而當AngularJS有使用到Transclude時,其實會建立一個獨立的Scope,也就是圖上的TranscludedScope…

其次,除了TranscluedScope外,AngularJS還會建立另外一個Scope…也就是IsolateScope…而IsolateScope會透過的$$nextSibling指向到TranscludedScope…

發現了嗎?..真實的底層,並不是我們想的,只有我們為Modal建立的Controller Scope…除了我們為Modal建立的Controller Scope外,還有兩個Scope!!

所以我們驗證一下,如下圖,我們可以看到他其實不是在我們Modal Controller的Scope,而是自己獨立的Scope….( Modal Controller的Scope為 Scope(004) ),所以可以確定$scope(007)為TranscluedScope

image

我們繼續驗證下去…當我們拉到Scope (006)的時候,我們可以看到$$nextSibling確實指向到了Scope(007),所以可以確定Scope(006)就是IsolateScope

image

也因此,實際上我們的Controller與定義畫面的model的Scope完全不同,自然Controller也呼叫不到…

但那為什麼用$parent.testText就可以呢??..因為$parent是代表上一層的意思(父層),而他的父層就是Controller,所以也就是代表在父層的Controller Scope定義了這個變數…

那oo.testText為什麼可以呢…如果ng-model=”oo.testText"這個變數應該也是會落在TranscluedScope上阿??

那是因為JavaScript原型繼承的特性…如果我們只打ng-model=”oo.testText",那的確還是會落在TranscluedScope上…

image

但如果今天,我們在Controller Scope裡面寫了$Scope.oo = {},則因JavaScript原型繼承的特性,當子物件要去定義oo.testText的時候,會先往上找到父層,看看有沒有oo這個物件,如果有的話,就實作於父層的oo下面,加上textText,若父層沒有,就會在子物件那邊,建立一個oo.testText…

基本上就是這樣…

最後,或許有人會說,那如果父層有oo,那我真的要在子物件去控制oo裡面的東西,不就會找不到oo!?,因為只有父層有oo啊!!?

但實際上,子Scope還是可以找的到oo,那是因為父層和子Scope都是參考到oo這個物件的記憶體位置~~

最後的最後,總之,這次的這個Case的原因,其實就是…我們的Controller實際上是屬於父層..但我們直接用ng-model=”testText”的時候,是在子Scope建立了這個變數,而非父層…,所以解決的方法,第一個就是告訴ng-model,要建立這個變數到父層喔!!,或是使用物件的方式,讓這個物件建立於父層~~

就是這樣!!~

後記

利用上班中午休息時間趕稿趕完XDDD,如有錯誤,也請大家多多包涵~~~

參考資料


Viewing all articles
Browse latest Browse all 144

Trending Articles


Re:Mutton Pies (lleechef)


Sapos para colorear


Break up Quotes Tagalog Love Quote – Broken Hearted Quotes Tagalog


Patama Quotes : Tagalog Inspirational Quotes


Pamatay na Banat and Mga Patama Love Quotes


5 Tagalog Relationship Rules


INUMAN QUOTES


Vimeo 10.7.0 by Vimeo.com, Inc.


Vimeo 10.7.1 by Vimeo.com, Inc.


Girasoles para colorear


Tagalog Quotes About Crush – Tagalog Love Quotes


OFW quotes : Pinoy Tagalog Quotes


Long Distance Relationship Tagalog Love Quotes


Tagalog Quotes To Move on and More Love Love Love Quotes


BARKADA TAGALOG QUOTES


Best Crush Tagalog Quotes And Sayings 2017


FORECLOSURE OF REAL ESTATE MORTGAGE