Javascript-форум (https://javascript.ru/forum/)
-   Angular.js (https://javascript.ru/forum/angular/)
-   -   из $Scope в функцию (https://javascript.ru/forum/angular/38912-iz-%24scope-v-funkciyu.html)

MaximusFT 07.06.2013 14:40

из $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 из примеров внутри контроллера...

Подскажите как можно сделать из Скопа - функцию чтобы внутри нее можно было вызывать другие Скопы и с ними работать.

just-boris 07.06.2013 22:20

Для начала, в angular есть встроенный сортировщик - orderBy.
А насчет ошибки, расскажите, пожалуйста, как вы вызываете функцию и саму эту функцию.

MaximusFT 07.06.2013 23:25

Контроллер страницы
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... и в каждом контроллере страницы есть одинаковые куски кода...

Я понимаю что может я говорю как Ламер... но я очень хочу разобраться...

just-boris 08.06.2013 01:07

я правильно понял, что вы хотите вызвать sortReorder в функции $scope.sortBy?

Shitbox2 08.06.2013 09:47

Кажется, что-то тут не так... $scope только для чтения в шаблонах и только для записи в контроллере. Вы же в своих функциях используете область видимости для получения данных. Тогда уж нужно присвоить модель переменной и работать уже с ней.
var model = Users.query(function(data){
$scope.items = model

Возможно, имеет смысл создать собственный фильтр и использовать его в контроллере с помощью сервиса $filter

Shitbox2 09.06.2013 15:05

Еще перевел статью по областям видимости: http://www.angular.ru/guide/understanding_scopes. Там как раз говорится о том, как пользоваться областями

DjDiablo 10.06.2013 07:38

Не знаю правильно ли я понял вопрос

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

вот кстатии хороший пример. 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);
}

MaximusFT 11.06.2013 15:03

Спасибо большое за советы, наверное мне не хватает банальных знаний об Объектах.
Можно еще один вопрос:

<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.
Почем Родитель теряет власть над областью после того как в нее было что-то записано дочерним контроллером...

Подскажите как можно обновлять информацию из одного контроллера в другом?

just-boris 15.06.2013 17:02

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

MaximusFT 15.06.2013 17:19

А принудительно как внести изменения в дочернем элементе?
Может проще отказаться от 2-х Контроллеров и делать все в одном?


Часовой пояс GMT +3, время: 08:47.