AngularJS: Как передать переменные между контроллерами?
У меня есть два контроллера Angular:
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
, потому что это undefined. Однако, если я попытаюсь передать его так...
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();
Также терпит неудачу.
ПРИМЕЧАНИЕ. Эти контроллеры не вложены внутри друг друга.
Ответы
Ответ 1
Один из способов обмена переменными через несколько контроллеров - создать сервис и ввести его на любом контроллере, где вы хотите его использовать.
Пример простого обслуживания:
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 и в частности).
Я обнаружил, что если вы хотите привязываться к этим свойствам на нескольких контроллерах, он работает лучше, если вы привязываетесь к свойству объекта вместо примитивного типа (логическое, строка, число) для сохранения связанной ссылки.
Пример: var property = { Property1: 'First' };
вместо var property = 'First';
.
ОБНОВЛЕНИЕ: Чтобы (надеюсь) сделать вещи более ясными вот скрипка, которая показывает пример:
- привязка к статическим копиям общего значения (в myController1)
- Связывание с примитивным (строка)
- Связывание с объектом (сохранено в переменной области)
- привязка к общим значениям, которые обновляют пользовательский интерфейс при обновлении значений (в myController2)
- Связывание с функцией, возвращающей примитив (строка)
- Привязка к свойству объекта
- Двусторонняя привязка к свойству объекта
Ответ 2
Мне нравится иллюстрировать простые вещи на простых примерах:)
Вот очень простой пример 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
Если это слишком просто, вот более сложный пример
Также см. ответ здесь для комментариев соответствующих рекомендаций
Ответ 3
--- Я знаю, что этот ответ не для этого вопроса, но мне нужны люди, которые читают этот вопрос и хотят обращаться с такими сервисами, как заводы, чтобы избежать неприятностей, делая это.
Для этого вам нужно будет использовать Сервис или Factory.
Услуги - это BEST PRACTICE для обмена данными между не вложенными контроллерами.
Очень хорошая аннотация на эту тему о совместном использовании данных - это объявление объектов. Мне не повезло, потому что я упал в ловушку AngularJS, прежде чем прочитал об этом, и я был очень расстроен. Поэтому позвольте мне помочь вам избежать этой проблемы.
Я прочитал из "ng-book: Полная книга по AngularJS", что AnggleJS ng-модели, созданные в контроллерах как голые данные, WRONG!
Элемент области $A должен быть создан следующим образом:
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 document) рекомендуется использовать (BEST PRACTICE), чтобы содержать вызовы как
<div ng-model="someModel.someValue"></div> //NOTICE THE DOT.
Это очень полезно для вложенных контроллеров, если вы хотите, чтобы ваш дочерний контроллер мог изменять объект с родительского контроллера....
Но в вашем случае вы не хотите вложенных областей, но есть аналогичный аспект для получения объектов от служб к контроллерам.
Предположим, что у вас есть ваша служба "Factory", а в обратном пространстве есть объект A, содержащий объект B, содержащий объект C.
Если с вашего контроллера вы хотите ПОЛУЧИТЬ objectC в свою область действия, это ошибка, чтобы сказать:
$scope.neededObjectInController = Factory.objectA.objectB.objectC;
Это не работает...
Вместо этого используйте только одну точку.
$scope.neededObjectInController = Factory.ObjectA;
Затем в DOM вы можете вызывать objectC из объекта A. Это наилучшая практика, связанная с заводами, и самое главное, , это поможет избежать неожиданных и неустранимых ошибок.
Ответ 4
Решение без создания Сервиса с использованием $rootScope:
Чтобы совместно использовать свойства в приложениях Controllers, вы можете использовать Angular $rootScope. Это еще один вариант для обмена данными, поэтому, чтобы люди знали об этом.
Предпочтительным способом обмена некоторыми функциями в контроллерах является "Сервис", чтобы читать или изменять глобальную собственность, вы можете использовать $anchcope.
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 в шаблоне (свойства Access с $root):
<div ng-controller="Ctrl1">
<div class="banner" ng-show="$root.showBanner"> </div>
</div>
Ответ 5
Образец выше работал как шарм. Я просто сделал модификацию на случай, если мне нужно управлять несколькими значениями. Надеюсь, это поможет!
app.service('sharedProperties', function () {
var hashtable = {};
return {
setValue: function (key, value) {
hashtable[key] = value;
},
getValue: function (key) {
return hashtable[key];
}
}
});
Ответ 6
Я склонен использовать ценности, довольные тем, кто может обсудить, почему это плохая идея.
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;
});
Ответ 7
Я хотел бы внести свой вклад в этот вопрос, указав, что рекомендуемый способ обмена данными между контроллерами и даже директивами - это использование сервисов (фабрик), как уже указывалось, но также я хотел бы чтобы представить практический пример того, как это сделать.
Вот рабочий плункер: 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>'
}
}]);
Надеюсь, что этот практичный и чистый ответ может быть полезен кому-то.
Ответ 8
В следующем примере показано, как передавать переменные между контроллерами siblings и выполнять действие при изменении значения.
Пример использования примера: у вас есть фильтр на боковой панели, который изменяет содержимое другого вида.
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>
Ответ 9
Не могли бы вы также сделать свойство частью родительского объекта?
$scope.$parent.property = somevalue;
Я не говорю это правильно, но он работает.
Ответ 10
Вы можете сделать это с помощью сервисов или заводов. Они по существу одинаковы для некоторых основных различий. Я нашел это объяснение на thinkster.io, чтобы это было проще всего следовать. Простой, точный и эффективный.
Ответ 11
А, у меня есть немного нового материала в качестве другой альтернативы. Это 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 в вашем контроллере.
Ответ 12
Есть два способа сделать это
1) Используйте услугу get/set
2)
$scope.$emit('key', {data: value}); //to set the value
$rootScope.$on('key', function (event, data) {}); // to get the value
Ответ 13
Второй подход:
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
Ответ 14
Если вы не хотите делать услугу, вы можете сделать это.
var scope = angular.element("#another ctrl scope element id.").scope();
scope.plean_assign = some_value;
Ответ 15
Помимо $rootScope и сервисов, существует простое и простое альтернативное решение для расширения angular для добавления общих данных:
в контроллерах:
angular.sharedProperties = angular.sharedProperties
|| angular.extend(the-properties-objects);
Эти свойства относятся к объекту 'angular', отделенному от областей, и могут использоваться совместно с областями и службами.
1 преимущество, которое вам не нужно вводить в объект: они доступны в любом месте сразу после вашей защиты!