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 и в частности).
Я обнаружил, что если вы хотите связать эти свойства с несколькими контроллерами, это будет работать лучше, если вы связываетесь со свойством объекта вместо примитивного типа (логическое, строка, число), чтобы сохранить привязанную ссылку.
Пример: 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;
});
И здесь очень просто 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;
});
Если это слишком просто, вот более сложный пример
Также см. Ответ здесь для соответствующих комментариев лучших практик
--- Я знаю, что этот ответ не для этого вопроса, но я хочу, чтобы люди, которые читают этот вопрос и хотят обращаться с такими Сервисами, как Фабрики, чтобы избежать проблем с этим ----
Для этого вам нужно будет использовать Сервис или Фабрику.
Сервисы - ЛУЧШАЯ ПРАКТИКА для обмена данными между не вложенными контроллерами.
Очень хорошая аннотация на эту тему об обмене данными о том, как объявлять объекты. Мне не повезло, потому что я попал в ловушку AngularJS, прежде чем я прочитал об этом, и я был очень расстроен. Итак, позвольте мне помочь вам избежать этой проблемы.
Из "ng-book: полная книга по AngularJS" я прочитал, что ng-модели AngularJS, созданные в контроллерах как голые данные, НЕПРАВИЛЬНЫ!
Элемент $ 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.
Это очень полезно для вложенных контроллеров, если вы хотите, чтобы ваш дочерний контроллер мог изменять объект из родительского контроллера....
Но в вашем случае вам не нужны вложенные области видимости, но есть аналогичный аспект для передачи объектов из сервисов в контроллеры.
Допустим, у вас есть сервис "Фабрика", и в возвращаемом пространстве есть объект A, который содержит объект B, который содержит объект C.
Если из вашего контроллера вы хотите получить objectC в вашу область, было бы ошибкой сказать:
$scope.neededObjectInController = Factory.objectA.objectB.objectC;
Это не сработает... Вместо этого используйте только одну точку.
$scope.neededObjectInController = Factory.ObjectA;
Затем в DOM вы можете вызвать objectC из objectA. Это лучшая практика, связанная с фабриками, и самое главное, она поможет избежать непредвиденных и неуловимых ошибок.
Решение без создания Сервиса с использованием $rootScope:
Для совместного использования свойств через контроллеры приложения вы можете использовать Angular $rootScope. Это еще один вариант обмена данными, чтобы люди знали об этом.
Предпочтительный способ обмена некоторыми функциями между контроллерами - это службы, для чтения или изменения глобального свойства вы можете использовать $ rootcope.
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;
});
В следующем примере показано, как передавать переменные между контроллерами одного уровня и выполнять действия при изменении значения.
Пример использования: у вас есть фильтр на боковой панели, который изменяет содержимое другого представления.
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>
Я хотел бы внести свой вклад в этот вопрос, указав, что рекомендуемый способ обмена данными между контроллерами и даже директивами - это использование сервисов (фабрик), как это уже указывалось, но я также хотел бы предоставить Рабочий практический пример того, как это должно быть сделано.
Вот рабочий плункер: 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>'
}
}]);
Надеюсь, что этот практичный и чистый ответ может быть полезным для кого-то.
Вы можете сделать это с помощью услуг или заводов. Они по сути одинаковы для некоторых основных различий. Я нашел это объяснение на сайте thinkster.io наиболее простым для подражания. Просто, точно и эффективно.
Второй подход:
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:
Ах, есть немного этого нового материала в качестве другой альтернативы. Это местное хранилище, и работает там, где работают угловые. Пожалуйста. (Но на самом деле, спасибо парню)
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 в свой контроллер.
Я просмотрел ответы выше, я рекомендую предложение Педжмана 29 декабря '16 в 13:31, но он / она не оставил полного ответа. Вот он, я поставлю это как -> (вам нужна служба и слушатель $watch на одной из областей от контроллеров для изменений в области обслуживания)
var app =
angular.module('myApp', ['ngRoute', 'ngSanitize']);
app.service('bridgeService', function () {
var msg = "";
return msg;
});
app.controller('CTRL_1'
, function ($scope, $http, bridgeService)
{
$http.get(_restApi, config)
.success(
function (serverdata, status, config) {
$scope.scope1Box = bridgeService.msg = serverdata;
});
});
app.controller('CTRL_2'
, function ($scope, $http, bridgeService)
{
$scope.$watch( function () {
return (bridgeService.msg);
}, function (newVal, oldVal) {
$scope.scope2Box = newVal;
}, true
);
});
Не могли бы вы также сделать свойство частью родительского объекта scopes?
$scope.$parent.property = somevalue;
Я не говорю, что это правильно, но это работает.
Есть два способа сделать это
1) Воспользуйтесь сервисом get/set
2)$scope.$emit('key', {data: value}); //to set the value
$rootScope.$on('key', function (event, data) {}); // to get the value
Если вы не хотите оказывать услуги, вы можете сделать это так.
var scope = angular.element("#another ctrl scope element id.").scope();
scope.plean_assign = some_value;
Помимо $rootScope и сервисов, существует чистое и простое альтернативное решение, позволяющее расширить угол добавления общих данных:
в контроллерах:
angular.sharedProperties = angular.sharedProperties
|| angular.extend(the-properties-objects);
Эти свойства принадлежат "угловому" объекту, отделены от областей и могут использоваться совместно в областях и службах.
1 преимущество в том, что вам не нужно вводить объект: они доступны где угодно сразу после вашего определения!