2015-01-14 459 views
7

不顯示新的實體開發一個角度應用程序,它包括一個功能建立一個目錄/嵌套樹結構...角嵌套指令模型

我遇到的問題是節點的渲染不太按預期工作。

當列表中已經有產品節點並且可以創建節時,似乎只顯示產品,但試圖將添加的小節添加到已添加的小節不會呈現。正如預期的一樣,節和產品節點正在插入模型中 - 只是指令似乎不在原始模型中不存在的節點上起作用。

相關代碼:

HTML

<head> 
    <meta charset="utf-8" /> 
    <title>AngularJS Plunker</title> 
    <script>document.write('<base href="' + document.location + '" />');</script> 
    <link rel="stylesheet" href="style.css" /> 
    <script data-require="[email protected]" src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.3.7/angular.js" data-semver="1.3.7"></script> 
    <script src="app.js"></script> 
</head> 

<body ng-controller="MainCtrl"> 
    <h1>Menu</h1> 
    <button ng-click="addSection()">Add</button> 
    <admin-sections sections="menu.sections"></admin-sections> 
</body> 

</html> 

JS

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

app.controller('MainCtrl', function($scope) { 
    $scope.menu = { 
    sections: [{ 
     name: "NEW SECTION 1", 
     sections: [{ 
     name: "NEW SECTION", 
     sections: [], 
     products: [{ 
      "name": "Product", 
      "price": "0.00" 
     }] 
     }], 
     products: [] 
    }] 
    }; 

    $scope.addSection = function() { 
    $scope.menu.sections.push({ 
     name: "NEW SECTION", 
     sections: [], 
     products: [] 
    }); 
    }; 
}); 

app 
    .directive('adminSections', function() { 
    return { 
     restrict: "E", 
     replace: true, 
     scope: { 
     sections: '=' 
     }, 
     templateUrl: 'sections.html' 
    }; 
    }) 
    .directive('adminSection', function($compile) { 
    return { 
     restrict: "E", 
     replace: true, 
     scope: { 
     section: '=' 
     }, 
     templateUrl: 'section.html', 

     link: function(scope, element, attrs, controller) { 
     if (angular.isArray(scope.section.sections) && scope.section.sections.length > 0) { 
      element.append($compile('<admin-sections sections="section.sections"></admin-sections>')(scope)); 
     } 
     if (angular.isArray(scope.section.products) && scope.section.products.length > 0) { 
      element.append($compile('<admin-products products="section.products"></admin-products>')(scope)); 
     } 

     scope.addSub = function(section) { 
      section.sections.push({ 
      "name": "NEW SECTION", 
      "sections": [], 
      "products": [] 
      }); 
     }; 

     scope.addProduct = function(section) { 
      section.products.push({ 
      "name": "Product", 
      "price": "0.00" 
      }); 
     }; 

     scope.deleteSection = function(section) { 
      var idx = scope.$parent.sections.indexOf(section); 
      scope.$parent.sections.splice(idx, 1); 
     }; 
     } 
    }; 
    }) 
    .directive('adminProducts', function() { 
    return { 
     restrict: "E", 
     replace: true, 
     scope: { 
     products: '=' 
     }, 
     templateUrl: 'products.html', 
     link: function(scope, element, attrs, controller) { 
     scope.editProduct = function(product) { 
      if (product.price === undefined) { 
      product.price = 0; 
      } 
      element.append($compile('<productform product="product"></productform>')(scope)); 
     }; 

     scope.deleteProduct = function(idx) { 
      if (confirm('Are you sure you want to delete this product?\n\nClick OK to confirm.')) { 
      scope.products.splice(idx, 1); 
      } 
     }; 
     } 
    }; 
    }) 
    .directive('adminProduct', function($compile) { 
    return { 
     restrict: "E", 
     replace: true, 
     scope: { 
     product: '=' 
     }, 
     templateUrl: 'product.html', 
     link: function(scope, element, attr, controller) { 

     scope.editProduct = function(product) { 
      if (product.price === undefined) { 
      product.price = 0; 
      } 
      element.append($compile('<productform product="product" />')(scope)); 
     }; 

     scope.deleteProduct = function(idx) { 
      scope.$parent.deleteProduct(idx); 
     }; 
     } 
    }; 
    }) 
    .directive('productform', function($compile) { 
    return { 
     restrict: "E", 
     replace: true, 
     scope: { 
     product: "=" 
     }, 
     templateUrl: 'productform.html', 
     link: function(scope, element, attrs, controller) { 
     scope.orig = angular.copy(scope.product); 
     scope.ok = function() { 
      element.remove(); 
      scope.$parent.editMode = false; 
     }; 

     scope.cancel = function() { 
      scope.reset(); 
      element.remove(); 
      scope.$parent.editMode = false; 
     } 

     scope.reset = function() { 
      scope.product = angular.copy(scope.orig); 
     } 
     } 
    }; 
    }); 

Plunker是在這裏:Angular Tree Menu

希望你能看到的意圖。

回答

3

問題在於,當鏈接指令時添加列表,具體取決於調用鏈接函數時的部分狀態(只有角度發現它時才執行一次)。

當你添加一個新的小節時,它會被鏈接,但是它的小節列表是空的,所以它沒有,並且生成的元素沒有小節,因爲你添加admin-sections,這取決於鏈接函數在小節時的狀態調用,所以不會添加任何嵌套的指令。

只需去除if語句應該足夠了(或者只是檢查,如果他們是數組):

element.append($compile('<admin-sections sections="section.sections"></admin-sections>')(scope)); 

element.append($compile('<admin-products products="section.products"></admin-products>')(scope)); 

這樣,ng-repeat在你的指令將觀看部分陣列中的每個部分,並相應地更新列表,而當數組爲空時保持空。

Working Plunker


至於如何嵌套的指令工作,這裏是當嵌套指令鏈接和控制器功能被稱爲一個很好的article

一般而言,controller s在解析任何內部指令之前運行,而link之後運行。所以,如果你有嵌套的指令是這樣的:

<outer-directive> 
    <inner-directive></inner-directive> 
</outer-directive> 

的順序是這樣的:

  1. 外指令控制器
  2. 內指令控制器
  3. 內部向鏈路
  4. 外指示鏈接

This i爲什麼當我試圖將admin-sections指令添加到每個部分的模板時,解析器進入了一個無限循環。解析每個部分意味着調用該部分小節的另一個link,但在外部admin-section的鏈接函數中使用$compile意味着它將在處理外部指令後解析。

此外,內部指令可以使用requiredocs)父指令來使用它們的控制器。

+0

圖例 - 我實際上刪除了batarang,因爲它似乎阻止了我的代碼的工作 - 刪除了允許發生的一些預期行爲,但我懷疑無限循環是實際原因...非常感謝 - 我確定它是某種東西簡單和一點理解如何綁定/觀察者功能是我明顯缺乏的東西。 –