I have 2 sortable, connected lists with pics: Album and Favorites.
When I drag and item from Album -> Favorites I want to check if it's already in the Favorites list.
If it is, do NOT accept it (maybe disable sorting or something?)
If it is not, clone the item back to the original index in Albums (connected sortable lists do only move items, so this mimics copying)
I have a function that checks if the pics are in the Favorites list:
function isInFavorites(url) {
return $(".favorites li img[src*='" + url + "']").length > 0;
}
This function works like expected...
However when I extract the scr attr with ui.item and pass the argument to this function I always get a true boolean??
var itemSrc = ui.item.find("img").attr("src");
if (isInFavorites(itemSrc)) { alert('item allready in favorites, do not accept'); }
else { alert('OK, now clone back to album'); }
I have been banging my head way to long on this and would appreciate some help!
A JS Fiddle can be found here: http://jsfiddle.net/tunafish/CTps3/
Cheers!
Not sure if this is the best way to process the logic but the order the events are firing is the source of your problem
function isInFavorites(url) {
return $(".favorites li img[src*='" + url + "']").length > 0;
}
This event runs AFTER the item has been moved. if it is a duplicate you will have length 2, but you will always have length 1 because you just moved the item into the lower list.
quick fix is to test for $(".favorites li img[src*='" + url + "']").length > 1
Related
https://jsfiddle.net/4byyuqtc/1/
I'm looking to have the ui-grid select all "children" under a grouping when the grouping line is selected. In this case Kit Kat(1), Mr. Goodbar(1), Krackel(2) and ultimately selecting the actual records (the non bold lines). One would expect that when selecting a parent in a grouping all it's children would get selected as well.
Currently when selecting the 1 grouping above the actual records in the data (the non bold lines) it does select those actual records with the following code:
$scope.gridApi.selection.on.rowSelectionChanged($scope, function (rowChanged) {
console.log(rowChanged.treeLevel);
if (typeof (rowChanged.treeLevel) !== 'undefined' && rowChanged.treeLevel > -1) {
// this is a group header
children = $scope.gridApi.treeBase.getRowChildren(rowChanged);
console.log(children);
children.forEach(function (child) {
if (rowChanged.isSelected) {
$scope.gridApi.selection.selectRow(child.entity);
} else {
$scope.gridApi.selection.unSelectRow(child.entity);
}
});
}
});
I'm not experienced enough with ui-grid at this point to figure out how to cycle through children of the selected line and select all of them.
[EDIT]
With Paul's code below it doesn't select the groupings but it's closer. This screenshot is me selecting the first 337 record. Notice it selects that record and all the lowest child records (which is good because ultimately those are the ones that matter) but visually the grouped records (MFG and Item Desc group) aren't selected and need to be as the user won't ever open the lowest data records so they need to see the groups selected.
I checked the documentation and I don't think there's any exposed API Method. You could recursively select/deselect rows as a solution. Please try out the example below.
$scope.gridApi.selection.on.rowSelectionChanged($scope, function (rowChanged) {
console.log(rowChanged.treeLevel);
if (typeof(rowChanged.treeLevel) !== 'undefined' && rowChanged.treeLevel > -1) {
var children = $scope.gridApi.treeBase.getRowChildren(rowChanged);
selectChildren(children, rowChanged.isSelected);
}
});
function selectChildren(gridRows, selected) {
if (gridRows && gridRows.length > 0) {
gridRows.forEach(function (child) {
if (selected) {
$scope.gridApi.selection.selectRow(child.entity);
} else {
$scope.gridApi.selection.unSelectRow(child.entity);
}
var children = $scope.gridApi.treeBase.getRowChildren(child);
selectChildren(children, selected); //recursively select/de-select children
});
}
}
Here's a working Plunkr: http://plnkr.co/edit/XsoEUncuigj9Cad1vP5E?p=preview
Handling automatic deselection is a bit more tricky though as it seems the api doesn't handle that really well.
UPDATE
So I checked the jsFiddle you shared and managed to get it working with a slight tweak.
I modified the selectionHandler to the following:
onRegisterApi: function(gridApi) {
$scope.gridApi = gridApi;
$scope.gridApi.selection.on.rowSelectionChanged($scope, function(rowChanged) {
if (rowChanged.treeNode.parentRow) { //Added this parent row selection
rowChanged.treeNode.parentRow.setSelected(rowChanged.isSelected);
}
console.log(rowChanged.treeLevel);
if (typeof(rowChanged.treeLevel) !== 'undefined' && rowChanged.treeLevel > -1) {
var children = $scope.gridApi.treeBase.getRowChildren(rowChanged);
selectChildren(children, rowChanged.isSelected);
}
});
Please see this fork of your code: https://jsfiddle.net/1eg5v77w/
The downside with this is that if you select a low level entry (one without children) it will still select its parent. If you really really want this to work as well, you'll have to access the DOM and make some ugly checks.
$scope.gridApi.selection.on.rowSelectionChanged($scope, function(rowChanged, $event) {
var wasHeaderRowClicked = true;
try { //This can be written more beautifully if you used jQuery. But I would still be against it as it relies on the class of the ui-grid never changing when you update your ui-grid version.
wasHeaderRowClicked = $event
.srcElement
.parentElement
.parentElement
.parentElement
.previousElementSibling
.firstChild
.firstChild
.firstChild
.getAttribute('class') === 'ui-grid-icon-minus-squared';
} catch(err) { console.log('Couldnt determine if header row was clicked'); }
if (rowChanged.treeNode.parentRow && wasHeaderRowClicked) {
rowChanged.treeNode.parentRow.setSelected(rowChanged.isSelected);
}
console.log(rowChanged.treeLevel);
if (typeof(rowChanged.treeLevel) !== 'undefined' && rowChanged.treeLevel > -1) {
var children = $scope.gridApi.treeBase.getRowChildren(rowChanged);
selectChildren(children, rowChanged.isSelected);
}
});
Here is the fiddle: https://jsfiddle.net/Lf8p7Luk/1/
I'd also like to add, thanks to this post, that according to the UI-Grid documentation: Group header rows cannot be edited, and if using the selection feature, cannot be selected. They can, however, be exported.
So it is intentional that it's so difficult to get this to work because it's not the intended design. My recommendation would be to alter your logic to either use Tree Levels or get around the selection logic because even though my fork is currently selecting everything, you will most likely run into other issues down the road. For example: I couldn't get automatic deselection to work in the grid when you click on another group header.
If you still have the issue take a look with this..
https://github.com/angular-ui/ui-grid/issues/3911
I have a tablesorter table that contains a 'Category' column. My searches reveal many different ways to filter on various types of columns but they all boil down to a single filter criteria.
What I have is a section on the page that lists all the categories with checkboxes, the idea is to allow the user to select which categories they want to look at (there are 10 different categories) and have these selected categories be applied to filter the rows in the tablesorter.
I could always brute force this with a post back to my controller and return a model with a filtered set of rows, but if there is a sensible way to accomplish this on the client side I would greatly appreciate anyones input on where to begin tackling a problem like this.
This is my first crack at it. So assume I have a bunch of checkboxes representing the categories to filter on. The class 'tablesorter' is what I called the table containing the data. I added an id attribute to the cell which has the category in it. I did it this way because I do not want the id to be visible on screen. At the end I refresh the zebra striping after hiding/unhiding rows. If there is a better way to do this, I'm all ears (I am a total newb to javascript/jquery/tablesorter).
function FilterCompanies() {
$(':checkbox:not(:checked)').each(function () {
var unselectedCategoryId = $(this).attr('id').substring(3);
$('.tablesorter > tbody > tr > td[id]').each(function() {
if ($(this).attr('id') == unselectedCategoryId) {
$($(this).parent()).addClass('hidden');
}
});
});
$(':checkbox:checked').each(function () {
var unselectedCategoryId = $(this).attr('id').substring(3);
$('.tablesorter > tbody > tr > td[id]').each(function () {
if ($(this).attr('id') == unselectedCategoryId) {
$($(this).parent()).removeClass('hidden');
}
});
});
$(".tablesorter").trigger("applyWidgets")
}
Here's what it looks like:
Couple of days ago I found this interesting post at http://www.smartjava.org/content/drag-and-drop-angularjs-using-jquery-ui and applied it into my website. However when I progressively using it there is a bug I identified, basically you can not move an item directly from one div to another's bottom, it has to go through the parts above and progress to the bottom. Anyone can suggest where does it goes wrong? The example is at http://www.smartjava.org/examples/dnd/double.html
Troubling me for days already.....
I did this a bit differently. Instead of attaching a jquery ui element inside the directive's controller, I instead did it inside the directive's link function. I came up with my solution, based on a blog post by Ben Farrell.
Note, that this is a Rails app, and I am using the acts_as_list gem to calculate positioning.
app.directive('sortable', function() {
return {
restrict: 'A',
link: function(scope, elt, attrs) {
// the card that will be moved
scope.movedCard = {};
return elt.sortable({
connectWith: ".deck",
revert: true,
items: '.card',
stop: function(evt, ui) {
return scope.$apply(function() {
// the deck the card is being moved to
// deck-id is an element attribute I defined
scope.movedCard.toDeck = parseInt(ui.item[0].parentElement.attributes['deck-id'].value);
// the id of the card being moved
// the card id is an attribute I definied
scope.movedCard.id = parseInt(ui.item[0].attributes['card-id'].value);
// edge case that handles a card being added to the end of the list
if (ui.item[0].nextElementSibling !== null) {
scope.movedCard.pos = parseInt(ui.item[0].nextElementSibling.attributes['card-pos'].value - 1);
} else {
// the card is being added to the very end of the list
scope.movedCard.pos = parseInt(ui.item[0].previousElementSibling.attributes['card-pos'].value + 1);
}
// broadcast to child scopes the movedCard event
return scope.$broadcast('movedCardEvent', scope.movedCard);
});
}
});
}
};
});
Important points
I utilize card attributes to store a card's id, deck, and position, in order to allow the jQuery sortable widget to grab onto.
After the stop event is called, I immediately execute a scope.$apply function to get back into, what Misko Hevery call,s the angular execution context.
I have a working example of this in action, up in a GitHub Repo of mine.
I have a page, which is used for building queries and running them against different entities (Kind of a query builder/generic search).
The results are displayed in JQGrid, so effectively the same grid will be used for rendering results from different entities.
This results grid has to support context menus, which will differ for each entity. So I need a way to change the context menu as per the entity. Each entity may have different number of menu items in context menu and each item may respond in a different manner (sometimes an alert, sometimes an action spawning in a different tab).
Rendering different menus (through li) is not an issue but attaching the methods to the li is proving to be a challenge. Any pointers will be highly appreciated.
I am using jquery.contextmenu-ui.js .
Following is from a sample that I picked from their (JQGrid) site
function initGrid() {
$("#EntityGrid").contextMenu('cMenu'
,{
bindings: { /* I would like to avoid this and pass all the actions to one method*/
'edit': function (t) {
editRow();
},
'add': function (t) {
addRow();
},
'del': function (t) {
delRow();
}
},
onContextMenu: function (event, menu) {
var rowId = $(event.target).parent("tr").attr("id")
var grid = $("#EntityGrid");
grid.setSelection(rowId);
return true;
}
}
);
}
Thanks,
Avinash
You can use onShowMenu callback of contextMenu instead of static binding using bindings. In the same way the menuId used as the first parameter of contextMenu could be the id of dynamically created div with empty <ul>. The onShowMenu has the form
onShowMenu: function (e, $menu) {
// here one can clear `<ul>` child of $menu
// and append it with "<li>" items
return $menu;
}
In the answer you will find an example of the code which build menu dynamically.
I want to be selected that new Item in list when I give new value to dataProvider but it selects the item that was firstly selected, and how to make that selected permanently on App start up.
You if want to select the list item after added to dataProvider. Probably you follow this
list.selectedIndex = list.dataProvider.length -1;
Sometimes if you added at desired position like
list.dataProvider.setItemAt(obj,2);
list.selectedIndex = 2
If you want to selected item permanently on App start up.(Make sure that your array collections bind-able to list)
public function onCreationComplete(event:FlexEvent):void
{
callLater(function():void
{
list.selectedIndex = list.dataProvider.length -1;
list.ensureIndexIsVisible(list.selectedIndex); // Viewport
});
}