AngularJS: как я могу передавать переменные между контроллерами?

у меня есть два угловых контроллеры:

function Ctrl1($scope) {
    $scope.prop1 = "First";
}

function Ctrl2($scope) {
    $scope.prop2 = "Second";
    $scope.both = Ctrl1.prop1 + $scope.prop2; //This is what I would like to do ideally
}

Я не могу использовать Ctrl1 внутри Ctrl2 потому что он не определен. Однако, если я попытаюсь передать его так...

function Ctrl2($scope, Ctrl1) {
    $scope.prop2 = "Second";
    $scope.both = Ctrl1.prop1 + $scope.prop2; //This is what I would like to do ideally
}

я получаю сообщение об ошибке. Кто-нибудь знает, как это сделать?

делаешь

Ctrl2.prototype = new Ctrl1();

тоже не получается.

Примечание: эти контроллеры не вложены друг в друга.

15 ответов


один из способов обмена переменными между несколькими контроллерами -создать службу и вставить его в любом контроллере, где вы хотите использовать его.

простой сервис, например:

angular.module('myApp', [])
    .service('sharedProperties', function () {
        var property = 'First';

        return {
            getProperty: function () {
                return property;
            },
            setProperty: function(value) {
                property = value;
            }
        };
    });

использование службы в контроллере:

function Ctrl2($scope, sharedProperties) {
    $scope.prop2 = "Second";
    $scope.both = sharedProperties.getProperty() + $scope.prop2;
}

это очень хорошо описано в этот блог (Урок 2 и в частности).

я обнаружил, что если вы хотите привязаться к этим свойствам через несколько контроллеров это работает лучше, если вы привязываетесь к свойству объекта вместо примитивного типа (boolean, string, number), чтобы сохранить привязанную ссылку.

пример: var property = { Property1: 'First' }; вместо var property = 'First';.


обновление: (надеюсь) сделать вещи более ясно вот скрипка это показывает пример:

  • привязка к статическим копиям общего значения (в myController1)
    • привязка к примитиву (строка)
    • привязка к свойству объекта (сохраняется в переменной области)
  • привязка к общим значениям, которые обновляют пользовательский интерфейс по мере обновления значений (в myController2)
    • привязка к функции, которая возвращает примитивное (строка)
    • привязка к свойству объекта
    • двусторонняя привязка к объекту собственность

мне нравится иллюстрировать простые вещи простыми примерами:)

вот очень простой Service пример:


angular.module('toDo',[])

.service('dataService', function() {

  // private variable
  var _dataObj = {};

  // public API
  this.dataObj = _dataObj;
})

.controller('One', function($scope, dataService) {
  $scope.data = dataService.dataObj;
})

.controller('Two', function($scope, dataService) {
  $scope.data = dataService.dataObj;
});

и вот jsbin

и вот очень простой Factory пример:


angular.module('toDo',[])

.factory('dataService', function() {

  // private variable
  var _dataObj = {};

  // public API
  return {
    dataObj: _dataObj
  };
})

.controller('One', function($scope, dataService) {
  $scope.data = dataService.dataObj;
})

.controller('Two', function($scope, dataService) {
  $scope.data = dataService.dataObj;
});

и вот jsbin


если это слишком просто, вот более сложный пример

и см. ответ здесь для связанных лучших практик комментарии


- - - - Я знаю, что этот ответ не для этого вопроса, но я хочу, чтобы люди, которые читают этот вопрос и хотят обрабатывать такие услуги, как фабрики, чтобы избежать проблем с этим - - - -

для этого вам нужно будет использовать сервис или фабрику.

услуги являются ЛУЧШАЯ ПРАКТИКА для обмена данными между не вложенными контроллерами.

очень очень хорошая аннотация по этой теме об обмене данными - это как объявить объекты. Мне не повезло, потому что я попал в ловушку AngularJS, прежде чем я прочитал об этом, и я был очень расстроен. Так позволь мне помочь тебе избежать этой проблемы.

Я прочитал из "ng-book: Полная книга об AngularJS", что AngularJS ng-модели, которые создаются в контроллерах как голые данные, ошибочны!

элемент $scope должен быть создан следующим образом:

angular.module('myApp', [])
.controller('SomeCtrl', function($scope) {
  // best practice, always use a model
  $scope.someModel = {
    someValue: 'hello computer'
  });

а не так:

angular.module('myApp', [])
.controller('SomeCtrl', function($scope) {
  // anti-pattern, bare value
  $scope.someBareValue = 'hello computer';
  };
});

это потому, что это рекомендуется(лучшая практика) для DOM (html-документ), содержащий вызовы как

<div ng-model="someModel.someValue"></div>  //NOTICE THE DOT.

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

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

Допустим, у вас есть свой сервис "Фабрика" , и в обратном пространстве есть объект, который содержит objectB, содержащий objectC.

если с вашего контроллера вы хотите получить objectC в свою область, это ошибка, чтобы сказать:

$scope.neededObjectInController = Factory.objectA.objectB.objectC;

это не сработает... Вместо этого используйте только одну точку.

$scope.neededObjectInController = Factory.ObjectA;

затем в DOM вы можете вызвать objectC из objectA. Это лучшая практика, связанная с фабриками, и самое главное,это поможет избежать неожиданных и неуловимых ошибок.


решение без создания сервиса, используя $rootScope:

для обмена свойствами между контроллерами приложений вы можете использовать Angular $rootScope. Это еще один вариант обмена данными, поставив его так, чтобы люди знали об этом.

предпочтительным способом обмена некоторыми функциями между контроллерами являются службы, для чтения или изменения глобального свойства вы можете использовать $rootscope.

var app = angular.module('mymodule',[]);
app.controller('Ctrl1', ['$scope','$rootScope',
  function($scope, $rootScope) {
    $rootScope.showBanner = true;
}]);

app.controller('Ctrl2', ['$scope','$rootScope',
  function($scope, $rootScope) {
    $rootScope.showBanner = false;
}]);

использование $rootScope в шаблоне (свойства доступа с $ root):

<div ng-controller="Ctrl1">
    <div class="banner" ng-show="$root.showBanner"> </div>
</div>

приведенный выше образец работал как шарм. Я просто сделал модификацию на случай, если мне нужно управлять несколькими значениями. Надеюсь, это поможет!

app.service('sharedProperties', function () {

    var hashtable = {};

    return {
        setValue: function (key, value) {
            hashtable[key] = value;
        },
        getValue: function (key) {
            return hashtable[key];
        }
    }
});

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

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

myApp.value('sharedProperties', {}); //set to empty object - 

затем введите значение согласно службе.

набор в контроль ctrl1:

myApp.controller('ctrl1', function DemoController(sharedProperties) {
  sharedProperties.carModel = "Galaxy";
  sharedProperties.carMake = "Ford";
});

и доступ из ctrl2:

myApp.controller('ctrl2', function DemoController(sharedProperties) {
  this.car = sharedProperties.carModel + sharedProperties.carMake; 

});

Я хотел бы внести свой вклад в этот вопрос, указав, что рекомендуемый способ обмена данными между контроллерами и даже директивами заключается в использовании служб (фабрик), как уже было указано, но также я хотел бы предоставить рабочий практический пример того, как это должно быть сделано.

вот рабочая plunker: http://plnkr.co/edit/Q1VdKJP2tpvqqJL1LF6m?p=info

во-первых,создать ваш сервис, что будет ваш общие сведения:

app.factory('SharedService', function() {
  return {
    sharedObject: {
      value: '',
      value2: ''
    }
  };
});

затем просто вставить его на свой контроллеры и захватить общие данные на вашей области:

app.controller('FirstCtrl', function($scope, SharedService) {
  $scope.model = SharedService.sharedObject;
});

app.controller('SecondCtrl', function($scope, SharedService) {
  $scope.model = SharedService.sharedObject;
});

app.controller('MainCtrl', function($scope, SharedService) {
  $scope.model = SharedService.sharedObject;
});

вы также можете сделать это для директивы, он работает так же:

app.directive('myDirective',['SharedService', function(SharedService){
  return{
    restrict: 'E',
    link: function(scope){
      scope.model = SharedService.sharedObject;
    },
    template: '<div><input type="text" ng-model="model.value"/></div>'
  }
}]);

надеюсь, что это практичный и чистый ответ может быть полезен кому-то.


в следующем примере показано, как передавать переменные между братья и сестры контроллеры и выполните действие при изменении значения.

пример использования: у вас есть фильтр на боковой панели, который изменяет содержимое другого представления.

angular.module('myApp', [])

  .factory('MyService', function() {

    // private
    var value = 0;

    // public
    return {
      
      getValue: function() {
        return value;
      },
      
      setValue: function(val) {
        value = val;
      }
      
    };
  })
  
  .controller('Ctrl1', function($scope, $rootScope, MyService) {

    $scope.update = function() {
      MyService.setValue($scope.value);
      $rootScope.$broadcast('increment-value-event');
    };
  })
  
  .controller('Ctrl2', function($scope, MyService) {

    $scope.value = MyService.getValue();

    $scope.$on('increment-value-event', function() {    
      $scope.value = MyService.getValue();
    });
  });
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>

<div ng-app="myApp">
  
  <h3>Controller 1 Scope</h3>
  <div ng-controller="Ctrl1">
    <input type="text" ng-model="value"/>
    <button ng-click="update()">Update</button>
  </div>
  
  <hr>
  
  <h3>Controller 2 Scope</h3>
  <div ng-controller="Ctrl2">
    Value: {{ value }}
  </div>  

</div>

Не могли бы вы также сделать свойство частью родительской области?

$scope.$parent.property = somevalue;

Я не говорю, что это правильно, но это работает.


Ах, есть немного этого нового материала в качестве другой альтернативы. Это localstorage, и работает там, где работает angular. Добро пожаловать. (Но на самом деле, спасибо парню)

https://github.com/gsklee/ngStorage

определите свои значения по умолчанию:

$scope.$storage = $localStorage.$default({
    prop1: 'First',
    prop2: 'Second'
});

доступ к значениям:

$scope.prop1 = $localStorage.prop1;
$scope.prop2 = $localStorage.prop2;

сохранить значения

$localStorage.prop1 = $scope.prop1;
$localStorage.prop2 = $scope.prop2;

не забудьте ввести ngStorage в приложение и $localStorage в контроллере.


вы можете сделать это с помощью услуг или заводов. Они, по сути, одинаковы для некоторых основных различий. Я нашел это объяснение на мыслитель.Ио быть самым легким следовать. Простой и эффективной.


есть два способа сделать это

1) Используйте get / set service

2) $scope.$emit('key', {data: value}); //to set the value

 $rootScope.$on('key', function (event, data) {}); // to get the value

Второй Подход :

angular.module('myApp', [])
  .controller('Ctrl1', ['$scope',
    function($scope) {

    $scope.prop1 = "First";

    $scope.clickFunction = function() {
      $scope.$broadcast('update_Ctrl2_controller', $scope.prop1);
    };
   }
])
.controller('Ctrl2', ['$scope',
    function($scope) {
      $scope.prop2 = "Second";

        $scope.$on("update_Ctrl2_controller", function(event, prop) {
        $scope.prop = prop;

        $scope.both = prop + $scope.prop2; 
    });
  }
])

HTML-код :

<div ng-controller="Ctrl2">
  <p>{{both}}</p>
</div>

<button ng-click="clickFunction()">Click</button>

дополнительные сведения см. В разделе plunker:

http://plnkr.co/edit/cKVsPcfs1A1Wwlud2jtO?p=preview


Если вы не хотите делать сервис, то вы можете сделать так.

var scope = angular.element("#another ctrl scope element id.").scope();
scope.plean_assign = some_value;

помимо $rootScope и сервисов, существует чистое и простое альтернативное решение для расширения angular для добавления общих данных:

в контроллеры:

angular.sharedProperties = angular.sharedProperties 
    || angular.extend(the-properties-objects);

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

1 преимущество в том, что вам не нужно вводить объект: они доступны в любом месте сразу после вашего дефинации!