dragular
dragular copied to clipboard
ngRepeat with orderBy problem
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?
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
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.
Ok I will check IE problem later tonight, and also try orderBy, let you know then.
There are some weird things happening, I will be solving this for a while, let you know when come up with something..
Thanks a lot!! If you could solve the orderBy issue it would be reeeeally appreciated :)
Have you tried the same code like in example above but replacing $filter('filter')
by $filter('orderBy')(collection, expression, reverse, comparator)
?
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;
};
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 ;)
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)
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;
I will be thinking about the solution and let you know when come out with something.
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. :/
Well, I'll definetly wait for your next library then :)