из $Scope в функцию
Изучаю Angular.
Я только делаю первые шаги, и сейчас делаю небольшое приложение, но дело в том что на многих страницах есть одинаковые $scope и соответственные функции. Пример $scope.items = Users.query(function(data){ $scope.paginator.setPages($scope.items.length); var i = 0; angular.forEach(data, function(v,k) { data[k]._id = i++; }); }); или $scope.sortBy = function() { var order = []; angular.forEach($scope.tablehead, function(h){ if (h.sort>0) order[h.sort-1] = h.name; if (h.sort<0) order[Math.abs(h.sort)-1] = '-'+h.name; }); return order; }; Но дубляж кода не есть хорошо, решил уменьшить код, сделать функции из этих скопов, но ни в какую, только ошибки в консоли в формате что не может вызвать $scope из функции пишет что "TypeError: Cannot call method 'slice' of undefined..." slice это метод, он есть если вызывать $scope из примеров внутри контроллера... Подскажите как можно сделать из Скопа - функцию чтобы внутри нее можно было вызывать другие Скопы и с ними работать. |
Для начала, в angular есть встроенный сортировщик - orderBy.
А насчет ошибки, расскажите, пожалуйста, как вы вызываете функцию и саму эту функцию. |
Контроллер страницы
function sortReorder(col,e,scope) { if (e.shiftKey) { var sortIndex = 0; angular.forEach(scope, function(el) { if (Math.abs(el.sort)>sortIndex) sortIndex = Math.abs(el.sort); }); angular.forEach(scope, function(el) { if (el.name==col) el.sort = el.sort?-el.sort:sortIndex+1; }); } else { angular.forEach(scope, function(el) { if (el.name==col) el.sort = el.sort>0?-1:1; else el.sort = null; }); } }; function UsersCtrl($scope, $routeParams, $location, Users) { $scope.items = Users.query(function(data){ $scope.paginator.setPages($scope.items.length); var i = 0; angular.forEach(data, function(v,k) { data[k]._id = i++; }); }); $scope.selected = []; $scope.paginator = { count: 20, page: 1, pages: 1, setPages: function(itemsCount){ this.pages = Math.ceil(itemsCount/this.count); } }; $scope.sortBy = function() { var order = []; angular.forEach($scope.tablehead, function(h){ if (h.sort>0) order[h.sort-1] = h.name; if (h.sort<0) order[Math.abs(h.sort)-1] = '-'+h.name; }); return order; }; $scope.sortReorder = function(col,e) { sortReorder(col,e,$scope.tablehead); }; } Обратите внимание на sortReorder, это удалось превратить в функцию... и вызывать ее в разных контроллерах... А вот из вот этого $scope.sortBy = function() { var order = []; angular.forEach($scope.tablehead, function(h){ if (h.sort>0) order[h.sort-1] = h.name; if (h.sort<0) order[Math.abs(h.sort)-1] = '-'+h.name; }); return order; }; не получается, и вот из этого в особенности хочется, так как это то что может правильно перегрузить содержимое таблицы на странице $scope.items = Users.query(function(data){ $scope.paginator.setPages($scope.items.length); var i = 0; angular.forEach(data, function(v,k) { data[k]._id = i++; }); }); Оба кода уникальны для всех страниц, сейчас у меня их уже 8... и в каждом контроллере страницы есть одинаковые куски кода... Я понимаю что может я говорю как Ламер... но я очень хочу разобраться... |
я правильно понял, что вы хотите вызвать sortReorder в функции $scope.sortBy?
|
Кажется, что-то тут не так... $scope только для чтения в шаблонах и только для записи в контроллере. Вы же в своих функциях используете область видимости для получения данных. Тогда уж нужно присвоить модель переменной и работать уже с ней.
var model = Users.query(function(data){ $scope.items = model Возможно, имеет смысл создать собственный фильтр и использовать его в контроллере с помощью сервиса $filter |
Еще перевел статью по областям видимости: http://www.angular.ru/guide/understanding_scopes. Там как раз говорится о том, как пользоваться областями
|
Не знаю правильно ли я понял вопрос
Но если у тебя есть общие куски кода в нескольких контролёрах тогда создайте собственный модуль с нужными методами и подключайте его в тех контролёрах где он вам необходим. Это обыкновенное модульное программирование. вот кстатии хороший пример. http://www.angular.ru/guide/dev_guid...ng_controllers Сервис предоставляющий множество методов можно как нибудь так описать angular.module('MyServiceModule', []). factory('notify', function() { return { fync1:function(){}, fync2:function(){}, fync3:function(){} } }); либо angular.module('MyServiceModule', []). factory('notify', function() { var f=function(){ //бла бла }, p=f.prototype; p.func1=function(){}; p.func2=function(){}; return new f(); //return f; если хочешь сам вызывать конструктор из контрола }); 3) Можно создать сервис users который будет возвращать не только данные но и методы работы с ними.(вероятно идеальное решение) 4) Придумал ещё один ход подобный примесям. Но сам бы я его пожалуй избегал до последнего. angular. module('MyServiceModule', []). factory('extendScope',function() { return function(scope) { scope.fn1=function(){}; scope.fn2=function(){}; scope.fn3=function(){}; return scope; } }); function myController(scope, extendScope) { extendScope(scope); // или scope=extendScope(scope); } |
Спасибо большое за советы, наверное мне не хватает банальных знаний об Объектах.
Можно еще один вопрос: <div class="span6" ng-controller="MyCtrl14"> MyCtrl14 > block14 = <br> <button ng-click="aMyCtrl14()">- ! -</button> <br> {{block14}} <div class="row show-grid"> <div class="span3"> IndexCtrl > block141 = <br> {{block141}} </div> <div class="span3" ng-controller="MyCtrl142"> MyCtrl142 > block142 = <br> <button ng-click="aMyCtrl142()">- ! -</button> <br> {{block142}} </div> </div> </div> function MyCtrl14($scope, notify) { $scope.block141 = '111'; $scope.aMyCtrl14 = function(){ $scope.block141 = '333'; $scope.block142 = '444'; } } function MyCtrl142($scope, newnoty) { $scope.aMyCtrl142 = function(){ $scope.block141 = '555'; $scope.block142 = '666'; } } 1) Нажимаем на кнопку "aMyCtrl14" - она вставляет оба значения block141 и block142. 2) Нажимаем на кнопку "aMyCtrl142" - она обновляет только значение block142. Понятно так как дочерняя не имеет по умолчанию возможности работать с областью родителей. НО! 3) Нажимаем на кнопку "aMyCtrl14" - она обновляет только значение block141. Почем Родитель теряет власть над областью после того как в нее было что-то записано дочерним контроллером... Подскажите как можно обновлять информацию из одного контроллера в другом? |
Потому что пока значение не определено, оно ищется у родителей вверх по цепочке. Потом оно перезаписывается локальным и больше не зависит от родителей.
|
А принудительно как внести изменения в дочернем элементе?
Может проще отказаться от 2-х Контроллеров и делать все в одном? |
На данный момент в портируемом проекте я использую один контроллер на страницу, всё остальное реализовано через директивы, все взаимосвязи указаны в атрибутах директив.
В твоём случае доступ к scope родителя можно получить через $scope.$parent если не ошибаюсь, после изменения parent можно опубликовать изменения при помощи $scope.$parent.$apply() |
Цитата:
$scope.paginator.setPages($scope.items.length); Такого быть не должно. Нужно как-то так: myService.paginator.setPages(items.length); $scope только для передачи данных в вид и такое его использование рано или поздно приведет к проблемам. Также можно использовать механизм событий $emit('MyEvent') и $broadcast('MyEvent') И писать как-то так $scope.$on('MyEvent', function() { $scope.count++; }); Ну или просто передавать данные через $rootScope и подписываться на них через $watch |
Цитата:
Нужно стремится по возможности к слабому связыванию компонентов. Это аксиома проектирования в любом языке, любом фреймворке, не зависимо от того какую программу вы пишете. Из красивых решений это атрибуты директив, либо события. Атрибуты деректив это в каком то смысле шлюзы компонентов, и через такие шлюзы можно относительно безопасно состыковывать компоненты UI между собой. Можно иметь общие данные для обсолютно независимых котролов и деректив, но придётся их хранить в сервисе и подключать сервис там где нужен доступ к этим данным. Вместе с данными в сервисе желательно хранить и методы обработки этих данных, такие методы можно будет вызывать из любого контрола где используется этот сервис (в 7ом посте писал об этом). Сделать сервис частью scope тоже труда не составляет. Сервис конечно не обеспечивает синхронизацию данных между различными компонентами, иными словами если один контроллер изменит данные в сервисе, то другой контроллер об этом изменении не узнает. Если нужна синхронизация то в качестве решения может проканать rootScope. Но так как обьект глобальный то злоупотреблять им не стоит, если всё пихать в rootScope то при изменении одних данных будет дёргаться слишком много лишних обработчиков watch. Довольно плохо если объекты и свойства в rootScope будут создаваться не централизованно а размазано по различным контроллерам, такое приложение будет сложно понимать. Из любопытных идей мне на ум приходит создание сервиса со своим cобственным scope. Такой финт позволит сочетать преимущества сервиса, с возможностью синхронизации при изменении данных при этом избегая универсального глобального объекта $rootScope. Получится что то вроде "активной модели". Однако в angular потребности в подобных инструментах у меня пока не возникало. Собрать же кучу скопов различных компонентов в одной функции это возможно худшее из всех возможных решений. |
Огромнейшее спасибо!
Буду переваривать информацию... так как скорее всего еще не до конца понял точку применения AngularJS. От сюда возник вопрос, но уже в новой теме. |
Часовой пояс GMT +3, время: 20:32. |