As I understand, ui-grid uses the primaryKey grid option to preserve your selection across updates, but this simple plunker shows this is not true:
http://plnkr.co/edit/WYXeQShHWKDYDs4MIZnP?p=preview
Steps to repro:
Click a row to select it
Click "click me to reset the data source". This will reset the data source (to a data source that contains exactly the same data as before).
Your selection is now gone.
The initial data source is:
data: [
{ id: "item1" },
{ id: "item2" }
],
With
primaryKey: 'id',
When you click on the button, here is the handler:
$scope.resetDataSource = function()
{
$scope.gridOptions.data = [ { id: "item1" }, { id: "item2" } ];
$scope.$apply();
};
Removing the $scope.gridOptions.data = line will preserve the selection just fine.
The new data source is exactly the same (contents) as the old.
What can I do to preserve selection after assigning a new data source?
Try to use option restoreSelection
http://ui-grid.info/docs/#/api/ui.grid.saveState.service:uiGridSaveStateService
Related
I have a div and a following javascript:
let usersNotContributingIds = [ 19, 20, 21 ];
let usersNotContributingNames = [ "Flavius K.", "Pogchamp", "Lazy Gopnik" ];
let contributorToBeAddedId; // the value that will be used for further actions
$("#alpaca-search-contributing-users").alpaca({
data: null,
schema: {
type: "object",
enum: usersNotContributingIds,
},
options: {
name: "pls",
label: 'Contributor Fullname',
optionLabels: usersNotContributingNames,
helper: "Select user sou want to add as a contributor",
id: "select2-search",
focus: false,
events: {
change: function() {
console.log(this.getValue().value);
contributorToBeAddedId = this.getValue().value
},
focus: function() {
console.log(this.name);
},
blur: function() {
console.log(this.name + ": blur");
},
ready: function() {
console.log(this.name);
}
},
},
postRender: function(control) {
$('#select2-search').select2();
}
});
Obviously, I want to get the newly set value, or anyhow access the selected value and use it. For example with AJAX and a button.
The problem is, that when I have 3 or less options, Alpaca render the field not as a search, but as a radio-something and the this.getValue() is null.
Is there a way to force Alpaca to NOT USE THE RADIO BUTTONS? I dont want to use them, even if I had only 1 option. Documentation just promtly states, that if there are 3 or less options, it will generate radio buttons instead of select, but it says nothing about the fact, that it breaks everything and that I would not be able to retrieve the value the same way as with select field.
If I am doing something inefficiently or wrong, please tell me, I am new with Alpaca and I just want a neat select dropdown with search, that I can use to pick users from a list with any length. Also, I would like the "null" or "none" option to not be there.
To have your select component rendered you should use the option type and set it to "select".
The issue with the value is because you're using it wrong, to get the value in alpaca you only do this.getValue() and there's no need to add .value.
FYI: If you see the error "This field should have one of the values in Flavius K., Lazy Gopnik, Pogchamp. Current value is: 19" you should update your enum array to have strings instead of ints let usersNotContributingIds = [ "19", "20", "21" ];.
Here's a working fiddle for this.
The idea I'm trying to achieve is to embed the datatable into the form.
For now, the form acts as a container. So far there are no any issues, but the name property for the datatable if ignored. The datatable not belongs to the form elements. AFAICS the following configuration is pretty common:
{
view:"form",
elements:[
{ view:"text", name:"inp1", value:"Test input" },
{ view:"datatable", name:"formDT", autoConfig:true, data:grid_data }
]
}
http://webix.com/snippet/7b7a8f2e
But if in the dataForm.elements I see only inputs.
Ideally, I want to get and set the datatable selection through the form's setValues and getValues methods. Or do I need to write my own method to gather the data from the inputs and the datatable separately? Has anyone faced such task before? TIA.
Here a custom component draft inherit datatable but support getValue setValue in order to act as a form input :
webix.protoUI({
name: "datatableInput",
defaults: {
},
$init: function(config) {
},
// Define component value (used by form setValues)
setValue: function(value) {
console.log('setValue');
this.clearSelection();
if (value) this.select(value);
},
// Get component value (used by form getValues)
getValue: function() {
console.log('getValue');
var item = this.getSelectedItem();
if (item) return item.id;
}
}, webix.ui.datatable);
Updated snippet :
http://webix.com/snippet/f952f35e
I have a datatable populated with aaData which is depicting the task created by users. Now, there is an action column in datatable which has two or three action buttons or logos like pdf - to view the user guide of that task, browse- link for the source code of the task and one is contributors logo which onclick should display the contributors for that particular task.
The aaData is of the following format which is populating the table
"aaData": [
[
"JSAG Home Page",
"JSAG Home page contains information about various POCs done",
"05/12/2012",
[
{
"displayValue":"Browse",
"link":"http://myTask.com/home",
"displayIcon" : "browselogo"
},
{
"displayValue":"Source Code",
"link":"svn/HomePage/trunk/",
"displayIcon" : "svnlogo"
},
{
"displayValue":"Audience Overview",
"link":"svn/Documents/Audience Overview.pdf",
"displayIcon" : "pdflogo"
},
{
"displayValue":"Contributors: ABC,XYZ",
"link":"#",
"displayIcon" : "people"
}
],
],
[
"Backlog",
"Backlog Forum application is designed to provide a platform for different groups to maintain backlog task items. ",
"25/08/2012",
[
{
"displayValue":"Browse",
"link":"http://mytask.com/BacklogApp",
"displayIcon" : "browselogo"
},
{
"displayValue":"Source Code",
"link":"svn/trunk/webapp-project/",
"displayIcon" : "svnlogo"
},
{
"displayValue":"Contributors: ABC",
"link":"#",
"displayIcon" : "people"
}
],
]
]
This format is for all datatables and contributors logo is there in all. What i wanted was, when user clicks the contributors icon, he should be able to see those contributors "ABC, XYZ, PQR".
I thought of fetching the action column data and then $each() the contributors array but i am not able to proceed with it.
How can i achieve this thing? How can i pick up the column value onclick because each datatable is being populated dynamically.
Please help.
Below is the code to populate a contributors div
$(document).on('click', '#contributor', function(contributors){
$.each(contributors, function(i, data) {
var ul_data = "<li><h3>"+ data+ "</h3></li>";
$("#contributors_div").append(ul_data);
});
}
$('#contributors_div').show();
});
How do i getrecentActdata as my contributors JSON array
Its going to be similar to this, provided you are declaring you datatable in the variable oTable
$(document).on('click', '#contributor', function(){
var aPos = oTable.fnGetPosition( $(this) );
console.log(aPos);
//if aPos returns an array in console, use first val at pos zero to get row data
var aData = oTable.fnGetData(aPos[0]);
console.log(aData);
// inspect your returned object, then tailor your $.each iteration
$.each( aData["contributors"], function(i, data) {
var ul_data = "<li><h3>"+ data+ "</h3></li>";
$("#contributors_div").append(ul_data);
});
}
$('#contributors_div').show();
});
I am attempting to use knockout-kendo.js to declare a kendo dropdownlist control in a knockout forEach template, so that as new items are added to the knockout observable array, new kendo dropdownlists are rendered in the UI.
Initially, I come to realize that I can no longer bind the dropdownlist's selected value to an entire entry object in my dropdownlist's specified 'data' array.
To overcome this issue, I followed the RP Niemeyer's suggestion in the following thread:
Set the binding of a dropdown in knockout to an object
Now, this all works. Great.
My issue is when attempting to add second drop down list to the template, who's data is bound to an array property on the object being returned from the computed observable... (I need to chain the drop down lists so that the first displays all Students, second displays all classes for the student that is currently selected in the first drop down list, third displays all test grades for the class that is currently selected in the second drop down list, etc....)
I created a fiddle based on RP Niemeyer's original fiddle to demonstrate my issue:
Original Fiddle (RP Niemeyer's)
My Fiddle With Issues
I added the below lines to the fiddle:
HTML:
<input data-bind="kendoDropDownList: { dataTextField: 'caption', dataValueField: 'id', data: selectedChoice().shapes, value: selectedShapeId }" />
JS:
this.choices = ko.observableArray([
{ id: "1", name: "apple", shapes: ko.observableArray([ { id: "5", caption: "circle" }, { id: "6", caption: "square" }]) },
{ id: "2", name: "orange", shapes: ko.observableArray([ { id: "5", caption: "circle" }]) },
{ id: "3", name: "banana", shapes: ko.observableArray([ { id: "5", caption: "circle" }, { id: "6", caption: "square" }, { id: "7", caption: "triangle" }]) }
]);
Again, I was expecting that upon the selection changing in the first drop down list (causing selectedId to change, causing selectedChoice to change) would also cause any UI elements bound to 'selectedChoice' or any of selectedChoices' properties, to have their bindings re-evaluated and UI respectively updated.
Am I missing something? Or is there a better way to achieve this 'chaining of drop down list' behavior (while still utilizing a knockout template and kendo drop down list control)?
Let me offer you some advice. Try to avoid accessing properties of an observable's value, as you can see, the dependency detection will not always be able to detect the dependency. You should create a computed observable which does the accessing for you.
var ViewModel = function () {
// ...
this.selectedChoice = ko.computed(function () {
var id = this.selectedId();
return ko.utils.arrayFirst(this.choices(), function(choice) {
return choice.id === id;
});
}, this);
this.selectedChoiceShapes = ko.computed(function () {
var selectedChoice = this.selectedChoice();
return selectedChoice && selectedChoice.shapes;
}, this);
}
Then your bindings becomes:
<input data-bind="kendoDropDownList: {
dataTextField: 'name',
dataValueField: 'id',
data: choices,
value: selectedId }" />
<input data-bind="kendoDropDownList: {
dataTextField: 'caption',
dataValueField: 'id',
data: selectedChoiceShapes,
value: selectedShapeId }" />
updated fiddle
This appears to be a shortcoming of Kendo using Knockout. When Kendo evaluates selectedChoice().shapes it holds onto the array it finds, instead of keeping the entire expression. If you update that specific array with options, you can see them in the second dropdown. The problem is that when you update selectedChoice Kendo does not reevaluate the data to the new shapes array. You can see this behavior in this fiddle.
Open the JS console, set the context to the fiddle (it defaults to the top frame in Chrome`, and run this:
window.vm.choices()[1].shapes.push({"id": "6", "caption" : "Thing"})
And you will see the second dropdown update. Changing the first dropdown doesn't have an effect. You can see that in this fiddle Knockout without kendo reevaluates the entire expression, properly updating the second select options.
I have two grids in my application.
var columns1 = [
{
name: "Address",
field: "address"
id: "address",
sortable: true
}
]
var columns2 = [
{
{
name: "Rating, in %",
field: "rating"
id: "rating_percent",
resizable: false
}
]
They are absolutely independent from each other. Also, I have some grid events descriptions in another js file.
grid.onColumnsReordered.subscribe(function (e, args) {
_this.updateHeaderRow();
// here
});
When user changes the columns order, then I want to save this order. Should I change (overwrite) the DOM elements, I mean column1 and column2?
So question: how can I save the columns order?
njr101's answer (using store.js) is great, but note: store.js cannot store functions (i.e. for editors, formatters), so once you store.get() the columns, you'll need to add the functions back, using your original stock "columns" array:
if (store.get('gridColumns')) {
grid.setColumns(store.get('gridColumns')); // Restore settings if available
grid.getColumns().forEach(function(ch) { // Re-create editor and formatter functions
var result = $.grep(columns, function(e){ return e.id == ch.id; });
if (result[0]) {
ch.editor = result[0].editor;
ch.formatter = result[0].formatter;
}
});
}
I have done this before and the easiest way I found was to store the columns in local storage. I use the store.js library which makes this pretty simple.
grid.onColumnsReordered.subscribe(function (e, args) {
store.set('gridColumns', grid.getColumns());
});
When you want to restore the columns (e.g. when the user returns to the page) you can just call:
grid.setColumns(store.get('gridColumns'));