2015-07-26 3 views
1

Я пытаюсь выяснить, как работает наследование контроллера. У меня есть три контроллера:Как работает угловой контроллер (и область) наследования

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

myApp.controller('MainController', ['$scope', function($scope) { 
    $scope.name = 'main'; 
    $scope.getName = function() { 
     return $scope.name; 
    }; 
}]); 
myApp.controller('Child1', ['$scope', function($scope) { 
    $scope.name = 'child1'; 
}]); 
myApp.controller('Child2', ['$scope', function($scope) { 
    $scope.name = 'child2'; 
}]); 

и мой взгляд

<div ng-app='app'> 
    <div ng-controller='MainController'> 
     <div ng-bind='getName()'></div> 

     <div ng-controller='Child1'> 
      <div ng-bind='getName()'></div> 

      <div ng-controller='Child2'> 
       <div ng-bind='getName()'></div> 
      </div> 
     </div> 
    </div> 
</div> 

, но они показывают, что все "главный". Как это исправить?

вот скрипка http://jsfiddle.net/g3xzh4ov/3/

ответ

2

Here's an example как контроллеры могут быть расширен в угловом.

myApp.service('baseCtrl', function() { 
    this.name = 'base'; 
    this.getName = function() { 
    return this.name; 
    }; 
}); 

myApp.controller('MainController', ['baseCtrl', function (baseCtrl) { 
    angular.extend(this, baseCtrl); 
    this.name = 'main'; 
}]); 
myApp.controller('Child1', ['baseCtrl', function (baseCtrl) { 
    angular.extend(this, baseCtrl); 
    this.name = 'child1'; 
}]); 
myApp.controller('Child2', ['baseCtrl', function (baseCtrl) { 
    angular.extend(this, baseCtrl); 
    this.name = 'child2'; 
}]); 

Это обязывает использовать controllerAs, заменяющий $scope с this, он особенно хорош для таких случаев.

Обратите внимание на использование service вместо других угловых видов обслуживания, оно использует new под капотом, поэтому операторы this... могут быть переведены с контроллера на отдельный сервис.

Существует несколько способов наследования контроллера. Вот another approach.

Что касается исходного кода, в «Угловом» отсутствует «контроллер iheritance». И $scope Прототипом наследования предполагает, что

$scope.getName = function() { 
    return $scope.name; 
}; 

возвращает $scope.name из контекста, в котором она была определена, это MainController функция в вашем случае.

1

Проблема, с которой вы столкнулись на самом деле базируются на основных функциях Javascript.

Вы видите, что замешательство, с которым вы сталкиваетесь, проистекает из сочетания обзора и прототипического наследования. Свойства скопированы, но область обзора остается неизменной, что препятствует доступу к переменным, которые вы ожидаете получить. Чтобы понять это лучше, может быть, вместо того, чтобы $scope, мы можем посмотреть на более простую переменную:

myApp.controller('MainController', ['$scope', function($scope) { 
    var a = 1; 
    $scope.getName = function() { 
     console.log(a); // -> 1 
     console.log(b); // Error! `Uncaught ReferenceError: b is not defined` 
    }; 
}]); 
myApp.controller('Child1', ['$scope', function($scope) { 
    var b = 2; 
}]); 

Очевидно, MainController не знает, что Child1 определены некоторые переменную b, так что ошибки. Эта переменная строго не лексическая.

Аналогично, если мы переименовали b в a, он не повернется значение в MainController 2. Это демонстрирует то, что происходит для вас: у вас есть три вещи, называемые $scope, и только один находится в лексической области.

два варианта, чтобы это исправить:

1) использование this:

$scope.getName = function() { 
    return this.name; 
}; 

this решение работает из-за того, как Javascript определяет "это" на основе контекста. В принципе, поскольку он привязан к заданному объекту $scope, этот объект является хорошим кандидатом. Но Mozilla может объяснить это лучше, чем я, поэтому просматривать их страницу на эту тему здесь: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this

2) В противном случае, вы можете просто передать $scope:

$scope.getName = function(item) { 
    return item.name; 
}; 
+1

Это будет отлично работать в его скрипке: http://jsfiddle.net/g3xzh4ov/4/. Никаких других изменений не требуется. Прототипическое наследование заботится о проблеме (если вы не используете 'bind') – DRobinson

0

Если вы хотите перезаписать свойство имени в дочерних областях, преобразуйте свойство примитивного имени в объект.

$scope.user = {}; 
$scope.user.name='main'; 
    $scope.getName = function() { 
     return $scope.user.name; 
    }; 

И вы должны прочитать https://github.com/angular/angular.js/wiki/Understanding-Scopes для получения более подробной информации.

Смежные вопросы