Skip to content
This repository has been archived by the owner on Nov 27, 2019. It is now read-only.

ngRepeat with orderBy problem #123

Open
Myrdivar opened this issue Feb 23, 2017 · 13 comments
Open

ngRepeat with orderBy problem #123

Myrdivar opened this issue Feb 23, 2017 · 13 comments

Comments

@Myrdivar
Copy link

Myrdivar commented Feb 23, 2017

I have a problem when I try to apply an orderBy to the ngRepeat because when I reorder an item it disappears from the container. Should I treat the orderBy like a normal filter? In that case I've seen this example:

http://luckylooke.github.io/dragular/#/docs/exampleNgRepeatFilteredWithModel

But even here when I move an item from left to right it disappears.

Any help?

@luckylooke
Copy link
Owner

But even here when I move an item from left to right it disappears.
I cannot reproduce this, could you tell me your OS and browser used? And also please tell me step by step to reproduce problem. thanks

@Myrdivar
Copy link
Author

Myrdivar commented Feb 23, 2017

You're right, in Chrome your example seems to work just fine but the first time I've tried with IE (v11.0.9600.18537 running on Win7 SP1). If you simply drag an element from the left container and drop on the other one it simply disappears. My problem with the orderBy instead occurs even in Chrome.

@luckylooke
Copy link
Owner

Ok I will check IE problem later tonight, and also try orderBy, let you know then.

@luckylooke
Copy link
Owner

There are some weird things happening, I will be solving this for a while, let you know when come up with something..

@Myrdivar
Copy link
Author

Thanks a lot!! If you could solve the orderBy issue it would be reeeeally appreciated :)

@luckylooke
Copy link
Owner

Have you tried the same code like in example above but replacing $filter('filter') by $filter('orderBy')(collection, expression, reverse, comparator) ?

@luckylooke
Copy link
Owner

I have tested orderBy filter combined with this example and it worked well ;)
Here is the change of getFilteredModel function in example:

$scope.getFilteredModel = function (filteredModel, items, filterQuery) {
    filteredModel.length = 0;
    var tmp = [];
    [].push.apply(tmp, $filter('filter')(items, filterQuery));
    [].push.apply(filteredModel, $filter('orderBy')(tmp, '+content'));
    return filteredModel;
  };

@luckylooke
Copy link
Owner

I have confirmed issue on IE, so I made separate github issue for it, not to be mixed with orderBy issue. Please tell me if my modification of getFilteredModel function worked for you. Thanks ;)

@Myrdivar
Copy link
Author

Myrdivar commented Mar 6, 2017

Yes, it seems to work but as long as I order by a "root" property of the list. With something like:

[].push.apply(filteredModel, $filter('orderBy')(tmp, 'property'));

it works but if I try:

[].push.apply(filteredModel, $filter('orderBy')(tmp, 'property.property'));

or the combined syntax:

[].push.apply(filteredModel, $filter('orderBy')(tmp, '[ -property, customFunction(), property.property ]'));

it seems to mix up indexes and elements start acting strange (even in chrome)

@luckylooke
Copy link
Owner

I have tested 'property.property' case and it works well when you move items from one container to another. It only have problem when you move item inside one container.

Problem description:
Dropped item get lost from view, because dragular removes dropped element to prevent duplicate item representation (one dropped element - which angular dont have coupled with model and one generated element by ng-repeat which angular have coupled with model).

In case of using orderBy filter sometimes items in model dont change position after drop, so angular dont redraw the ng-repeat view and so this is the problem where item get lost.. in model it still exists, but in view it never become redrawn unless model changed.

My test code:

'use strict';

var NgRepeatFilteredWithModelCtrl = function ($scope, $element, dragularService, $filter) {
	$scope.items1 = [{
		propty: {prop2: 'd'},
		content: 'Apple 1'
	}, {
		propty: {prop2: 'f'},
		content: 'Apple 2'
	}, {
		propty: {prop2: 'a'},
		content: 'Apple 3'
	}, {
		propty: {prop2: 'c'},
		content: 'Orange 4'
	}, {
		propty: {prop2: 'v'},
		content: 'Orange 5'
	}, {
		propty: {prop2: 'h'},
		content: 'Apple 6'
	}, {
		propty: {prop2: 'f'},
		content: 'Apple 7'
	}, {
		propty: {prop2: 'k'},
		content: 'Apple 8'
	}];
	$scope.items2 = [{
		propty: {prop2: 'u'},
		content: 'Apple 9'
	}, {
		propty: {prop2: 'e'},
		content: 'Orange 10'
	}, {
		propty: {prop2: 's'},
		content: 'Orange 11'
	}, {
		propty: {prop2: 'u'},
		content: 'Apple 12'
	}, {
		propty: {prop2: 'v'},
		content: 'Orange 13'
	}, {
		propty: {prop2: 'n'},
		content: 'Apple 14'
	}];
	$scope.filter1query = 'Orange';
	$scope.filter2query = 'Orange';
	$scope.filteredModel1 = [];
	$scope.filteredModel2 = [];
	$scope.getFilteredModel = function (filteredModel, items, filterQuery) {
		filteredModel.length = 0;
      /*
       * Following one-liner is same like:
       *   var filteredModelTemp = $filter('filter')(items, filterQuery);
       *   angular.forEach(filteredModelTemp, function(item){
       *     filteredModel.push(item);
       *   });
       * Or like:
       *   var filteredModelTemp = $filter('filter')(items, filterQuery);
       *   for(var i; i < filteredModelTemp.length; i++){
       *     filteredModel.push(filteredModelTemp[i]);
       *   }
       *
       * You cannot just assign filtered array to filteredModel like this:
       *   filteredModel = $filter('filter')(items, filterQuery);
       * Because you would replace the array object you provide to dragular with new one.
       * So dragular will continue to use the one it was provided on init.
       * Hopefully I make it clear. :)
       */
		// [].push.apply(filteredModel, $filter('filter')(items, filterQuery));

		console.log('input', JSON.stringify(items, null, '\t'));

		// Example with orderBy filter:
		var tmp = [];
		[].push.apply(tmp, $filter('filter')(items, filterQuery));
		[].push.apply(filteredModel, $filter('orderBy')(tmp, 'propty.prop2'));

		console.log('output', JSON.stringify(filteredModel, null, '\t'));
		return filteredModel;
	};
	var containers = $element.children().eq(1).children();
	dragularService.cleanEnviroment();
	dragularService([containers[0],containers[1]],{
		containersModel: [$scope.items1, $scope.items2],
		containersFilteredModel: [$scope.filteredModel1, $scope.filteredModel2]
	});
};

NgRepeatFilteredWithModelCtrl.$inject = ['$scope', '$element', 'dragularService', '$filter'];

module.exports = NgRepeatFilteredWithModelCtrl;

@luckylooke
Copy link
Owner

luckylooke commented Mar 10, 2017

I will be thinking about the solution and let you know when come out with something.

@luckylooke
Copy link
Owner

This is very complicated situation, how to handle the case when item from same container is dropped but view is not changed because it is ordered into same order.

Here is what is happening after drop:

  • dragular moves item model in non-filtered model array, remove dropped element because it is not coupled with data in ng-repead internal map
  • angular recalculate ng-repeat and find out that result of filtering function is the same so thinks no real change occured and view supposed to be the same

I was looking for something to tell ng-repeat to redraw its content, but did not found anything simple enough

So I recommend not allowing sorting in containers using orderBy filters! Until someone becomes with better soluton. Sorry for problems, but I cannot handle every possible scenario.

PS:
I am preparing better library with much better control, and I think it would be much more easier to solve your scenario, but it is not ready yet. :/

@Myrdivar
Copy link
Author

Well, I'll definetly wait for your next library then :)

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

2 participants