I have a very basic CellTable in GWT right now and use a majority of the code shown here.
However when I toggle a checkbox, every single row gets highlighted.
Preview: gfycat
I did try so far:
Multi-/SingleSelectionMode: (I only want to get one row, so I would prefer SingleSelectionMode)
CheckBoxCell(true, true): -> This is exactly how I want the CellTable to look, however with these parameters I can't get an object with "getSelectedObject()". Other variations of the parameters(false,false/true, false) also didn't seem to work
CellTable<Article> ArticleCt = new CellTable<Article>(KEY_PROVIDER);
ListHandler<Article> sortHandler = new ListHandler<Article>(Articles);
ArticleCt.addColumnSortHandler(sortHandler);
final MultiSelectionModel<Article> selectionModel1 = new MultiSelectionModel<Article>(KEY_PROVIDER);
ArticleCt.setSelectionModel(selectionModel1, DefaultSelectionEventManager.<Article> createCheckboxManager());
Column<Article, Boolean> checkColumn = new Column<Article, Boolean>(
new CheckboxCell(true, false)) {
public Boolean getValue(Article object) {
return selectionModel1.isSelected(object);
}
};
I want to have only the row with the checked checkbox selected so I can fetch the peticular row/object with selectionMode.getSelectedObject() or selectionMode.getSelectedSet().
However every single row gets highlighted.
Your key provider, KEY_PROVIDER in the question above, must provide unique and consistent keys per row. For example, each row might have an "ID" field.
If more than one row shares a key, then selecting one seems to be the same to the selection model as selecting both. If a row's key is not consistent, then when a row is selected, it can't be queried later since its key changed.
Related
Is there a way to pre-select a value or values for the filter checkbox?
I am currently saving the last filter so if a user filters, leaves the page, and then comes back the grid is still filtered. The issue I'm having is the filter drop down checkboxes does not reflect the filtered rows.
Here is the code I am using to set the saved filter:
if ($scope.onFilterChanged) {
this.gridOptions.onFilterModified = function () {
$scope.onFilterChanged({filter: ctrl.gridOptions.api.getFilterModel()});
}
}
if ($scope.currentFilter && $scope.onFilterChanged) {
this.gridOptions.api.setFilterModel($scope.currentFilter);
} else {
this.gridOptions.api.setFilterModel(null);
}
setFilterModel works great if I'm not leaving the page and coming back. But I'm not sure why it updates the rows and not the drop down options on page load..Is there a way to get the filtered rows and the check boxes to match on page load?
Yes its possible via filter API
You need to get filter instance first
let filterInstance = this.gridOptions.api.getFilterInstance('columnNameHere');
Then you can decide what should be in the filter
filterInstance.selectNothing();
filterInstance.selectValue("value one");
filterInstance.selectValue("value two");
...or...
let model = ["value one", "value two"];
filterInstance.setModel(model);
And on the last step - just inform the grid about changes
this.gridOptions.api.onFilterChanged();
Explanation
I have a very simple calorie tracking app that uses the Nutritionix API to search for food items based on the user's input. The results are added to a results array, which is then displayed to the user. When a user clicks the "Add" button next to one of these items, the calories are added to a counter, and the food itself is added to a todaysFood array (using Ember's pushObject). This is then used to display which food the user has consumed today in a separate table.
When a user clicks the remove button next to one of the todaysFood items, it triggers an action, removeItem, and passes the index of the item clicked to removeItem. This index is used inside of Ember's removeObject to remove the item from the todaysFood array, and thus update the view (remove that item from the list and its calories from the counter).
Problem
When more than one of the same item are added to todaysFood, clicking remove on just one of those items removes ALL of the instances from todaysFood, and the view. This makes sense to me now, because of the docs' example:
var cities = ['Chicago', 'Berlin', 'Lima', 'Chicago'];
cities.removeObject('Chicago'); // ['Berlin', 'Lima']
cities.removeObject('Lima'); // ['Berlin']
cities.removeObject('Tokyo') // ['Berlin']
However, it also only removes the calories of ONE item, not all instances.
So, the question is: How do I remove only ONE instance of that item when remove is clicked? I.e., if two tacos are added, and I click remove on one, I only want that ONE to be removed (from the list and the calories).
Here is my removeItem action:
removeItem(index) {
var self = this;
// Store property paths for easy access
let todaysPath = this.get('healthData').todaysFood;
let caloriesPath = 'healthData.calories';
this.set(caloriesPath, this.get(caloriesPath) - Math.round(todaysPath[index].fields.nf_calories));
todaysPath.removeObject(todaysPath[index]);
}
Disclaimer
I'm aware that I may not be handling this correctly at all. I'm open to any suggestions to make this better. Thanks!
You have index of object to remove so you can try using removeAt() method:
todaysPath.removeAt(index);
I have a form that can submit a number of rows of data associated with a given date. One of those fields is a percentage (i.e.: 0-100). I could have three rows of a given date with percentages that add up to 100 (or not, but that's a different validation issue) or two rows with different dates and associated percentages, etc.
I need to keep track of everything and sort all the percentages into the right date buckets on submission so I can do my validation.
To that end, I created an array, PctArray. Each element of PctArray is a two field Object - date, pct. As I loop through submitted data, I check each row's date to see if it's in the PctArray already, and, if so, increment the associated pct field of that date and move on. If not, I create a new element in PctArray and insert the information.
This all works fine and dandy if there's only one row submitted, or even several rows for one date. But the minute I submit information for a second date, it chokes. At this point, I give you the code:
// If this is our first row to process
if(PctArray.length == 0){
PctArray[0] = new Object();
PctArray[0].effdt = datefield.options[datefield.selectedIndex].value;
PctArray[0].pct = parseInt(pctfield.value);
}
else{
// We loop through the array to see if this EffDt exists yet. Not very efficient, but the array will always be small
var found = "no";
for(p=0;p<PctArray.length;p++){
if(PctArray[p].effdt == datefield.options[datefield.selectedIndex].value){
PctArray[p].pct = PctArray[p].pct + parseInt(pctfield.value);
found = "yes";
}
}
if(found == "no"){
PctArray[PctArray.length] = new Object();
PctArray[PctArray.length].effdt = datefield.options[datefield.selectedIndex].value;
PctArray[PctArray.length].pct = pctfield.value;
}
}
The initital take, when it's the first row, everything creates and inserts just fine. But, when I need to go into the block of if(found == "no") it creates the new element, but then dies on the first assignment statement saying Unable to set value of the property 'effdt': object is null or undefined.
I don't get it. I'm declaring the new element the SAME EXACT WAY in both places, but there's something I'm missing that it's not liking about the second time.
I've also tried replacing new Object() with {"effdt":'', "pct":''} with identical results. It works on the top one, not the bottom one.
I'm lost. Does anyone see what I'm missing here?
Thanks.
PctArray[PctArray.length] = new Object();
PctArray[PctArray.length].effdt = datefield.options[datefield.selectedIndex].value;
After the first assignment PctArray.length has increased so you are trying to address non-existing element. You may improve the code by combining your assignments without expllicit new Object():
PctArray.push(
{ effdt: datefield.options[datefield.selectedIndex].value
, pct: pctfield.value
})
How can I exempt a single row in a DataTables.js table from DataTables' builtin filtering, so thta it is always shown?
Background: I'm building a table editing component using the jQuery-based DataTables.js library. Instead of using dialogs or overlays, I wanted to present editing controls right within the datatable, like this:
This works like a charm, even with active filters: I keep the original, unchanged data in the record while it is being edited, so I can use that data for the 'sort' and 'filter' modes of mDataProp, and my row stays in place and visible until editing is finished.
A bigger problem arises when I add a new row: There is no data to use for filtering, so if a filter is active, my row won't be visible. This breaks the workflow where the user searches through the dataset, sees that some record is missing, and (without clearing the filter) presses the "Add" button, waiting for an empty row with edit controls to appear:
How can I exempt this special row from DataTables' filtering?
After reading through the source code of DataTables.js for some time, I came to the conclusion that there is no way to hook into the filtering in the desired way. There are hooks for custom filters, but they can only be used to hide stuff, not to show stuff.
However, there's a 'filter' event which is triggered after filtering, but before the table is rendered. My solution installs an handler for this event:
$('table#mydatatable').bind('filter', function() {
var nTable = $(this).dataTable();
var oSettings = nTable.fnSettings();
//collect the row IDs of all unsaved rows
var aiUnsavedRowIDs = $.grep(oSettings.aiDisplayMaster, function(iRowID) {
var oRowData = nTable.fnGetData(iRowID);
return is_unsaved(oRowData);
});
//prepare lookup table
var oUnsavedRecordIDs = {};
$.each(aiUnsavedRowIDs, function(idx, iRowID) {
oUnsavedRecordIDs[iRowID] = true;
});
//remove unsaved rows from display (to avoid duplicates after the
//following step)
for (var i = oSettings.aiDisplay.length; i >= 0; i--) {
//iterate backwards, because otherwise, removal from aiDisplay
//would mess up the iteration
if (oUnsavedRecordIDs[ oSettings.aiDisplay[i] ]) {
oSettings.aiDisplay.splice(i, 1);
}
}
//insert unsaved records at the top of the display
Array.prototype.unshift.apply(oSettings.aiDisplay, aiUnsavedRowIDs);
//NOTE: cannot just say oSettings.aiDisplay.unshift(aiUnsavedRowIDs)
//because this would add the array aiUnsavedRowIDs as an element to
//aiDisplay, not its contents.
});
What happens here? First, I find all unsaved rows by looking through oSettings.aiDisplayMaster. This array references all rows that are in this DataTable, in the correct sorting order. The elements of aiDisplayMaster are integer indices into DataTables' internal data storage (one index per row).
The filtering process goes through the rows in aiDisplayMaster, and places the row IDs of all matching rows in oSettings.aiDisplay. This array controls which rows will be rendered (after this event handler has finished!). The whole process looks like this:
[1, ..., numRows]
|
| sorting
v
oSettings.aiDisplayMaster
|
| filtering
v
oSettings.aiDisplay
|
| rendering
v
DOM
So after having located all unsaved records in aiDisplayMaster (using custom logic that I wrapped in an is_unsaved() function for the sake of this snippet), I add them all to aiDisplay (after removing existing instances of these rows, to avoid duplicates).
A side-effect of this particular implementation is that all unsaved rows appear at the top of the table, but in my case, this is actually desirable.
I have the following code from selected rows in a grid......
var selected_rows = grid.getSelectionModel().getSelections();
Ext.each(selected_rows,function(item) {
var left_thumbnail_jpeg_name =item.data.left;
var right_thumbnail_jpeg_name = //select second cell along row
Can someone tell me how to set the second cell value along the row to a variable?
James
Please note that your tags did not include ExtJS and that is a bit misleading.
As for your question, since your grid in bound to a store of records you only need to change a record value for it to be imminently rendered to the grid.
in your case it will be :
item.set('right', YOUR NEW VALUE);
assuming that the next column is named right and that you have the new new value.