Angularjs: UI-Grid dynamic dropdown for each row - angular-ui-grid

I am using 'ui-grid/dropdownEditor' for one of my column and I want to dynamically load the drop down options which is unique for each row. I want to load the drop down options dynamically on demand via async http call.
I tried the following without success,
$scope.gridOptions = {
columnDefs: [
{ field: 'priority',
displayName: 'Priority',
editableCellTemplate: 'ui-grid/dropdownEditor',
editDropdownIdLabel: 'id',
editDropdownValueLabel: 'name',
},
]}
onRegisterApi: function(gridApi) {
gridApi.edit.on.beginCellEdit($scope, function(rowEntity, colDef) {
if (colDef.field === "priority") {
localServices.getPriorityById(rowEntity.id).then(function(data) {
colDef.editDropdownOptionsArray = data;
});
}
});
Any suggestion or help to achieve this is appreciated.

You should look into the usage of editDropdownRowEntityOptionsArrayPath instead of editDropdownOptionsArray
editDropdownRowEntityOptionsArrayPath can be used as an alternative to
editDropdownOptionsArray when the contents of the dropdown depend on
the entity backing the row.
Here is a link to tutorial

Related

Tabulator copyToClipboard method isn't working as anticipated

I am new to the Tabulator plug-in and I am attempting to copy data from one table to another using the Tabulator copyToClipboard method but with no success.
In my application I have created eleven <div> elements (one for the [Crew Leader] and one each for up to ten [Crew Members]) to serve as containers for the Tabulator tables to be instantiated. I am hoping to copy data from the [Crew Leader] table and paste it into each of the affected [Crew Member] tables thus mitigating data re-entry. This sequence of copy/paste events is triggered by the click event bound to a <button> in the header of the [Crew Leader] table. The following function is called by the <button> click event:
function CloneTable() {
// Verify the [Crew Leader] Tabulator table is present....
var tableLeader = Tabulator.prototype.findTable("#CrewLeaderTable");
if (tableLeader.length > 0) {
alert("The Tabulator table #CrewLeaderTable was found.\ntable.length = " + tableLeader.length);
tableLeader.copyToClipboard("all");
alert("The table contents were copied to the clipboard.");
}
else {
alert("The Tabulator table #CrewLeaderTable was not found.");
}
}
The first alert message verifies that the #CrewLeaderTable object has been found as anticipated. However, the second alert verification is never received thus indicating failure of the Tabulator copyToClipboard method.
I have read through as much of the relevant Tabulator documentation as I can find and I am hoping I have simply overlooked something in my setup.
The following is a copy of my Tabulator constructor:
var table = new Tabulator(divid, {
height: "100%",
layout: "fitDataFill",
movableRows: true, //enable user movable rows
tabEndNewRow: true, //create empty new row on tab
rowContextMenu: myActionContextMenu,
keybindings: {
"navUp": true, //enable navUp keybinding using the "up arrow" key
"navDown": true, //enable navDown keybinding using the "down arrow" key
},
columns: [
{ title: "Phase Code", field: "phaseCode", width: 144, editor: "select", editorParams: { values: function (cell) { return window.laborPhaseCodes; } } },
{ title: "Date Worked", field: "dateComp", hozAlign: "center", sorter: "date", editor: dateEditor },
{ title: "Start Time", field: "timeStart", hozAlign: "center", sorter: "time", editor: timeEditor },
{ title: "Finish Time", field: "timeFinish", hozAlign: "center", sorter: "time", editor: timeEditor },
{ title: "Memo", field: "memo", width: 144, hozAlign: "left", editor: "input" },
{ title: "<button type='button' id='btnClone' class='btn btn-success btn-sm py-0' style='font-size:10px;'>Clone</button>", headerSort: false, headerClick: tabCloneTable }
],
cellEdited: function (cell) {
}
});
I have spent a couple of days trying to figure out the best way to "clone" the data from one table into another. The Tabulator documentation is fairly comprehensive but I fear I have overlooked something. Any assistance is greatly appreciated.
It looks like copyToClipboard doesn't return the data, it is maintained internally and not accessible. But, with what you are doing set/getData works fine.
Here is an example, https://jsfiddle.net/nrayburn/19sjg74k/7/.
Basically, what you want to do is call getData on the parent table and setData on the child table.
const crewLeaderTable = Tabulator.prototype.findTable('#CrewLeaderTable')[0];
const crewMemberTable = Tabulator.prototype.findTable('#CrewMember1Table')[0];
const crewLeaderData = crewLeaderTable.getData();
// You could also use replaceData or addData, depending on the requirements
crewMemberTable.setData(crewLeaderData);

ASP.Net MVC 6 Cascading Dropdowns Not Populating [duplicate]

This question already has answers here:
Clear and refresh jQuery Chosen dropdown list
(7 answers)
Closed 6 years ago.
I'm using cascading dropdowns on a page. The first dropdown is being filled from ViewBag
#Html.DropDownList("OrgGroupID",
(IEnumerable<SelectListItem>)ViewBag.OrgGroups,
new Dictionary<string, object>
{
{ "class", "form-control" },
{ "width", "100%" },
{ "data-placeholder", "Select Group..." },
{ "onchange", "groupSelected(this)" }
})
and the second one is being filled when a value is selected from first one. The markup for second dropdown is
#Html.ListBox("Devices",
(IEnumerable<SelectListItem>)ViewBag.Devices,
new Dictionary<string, object>
{
{ "id", "devices"},
{ "class", "chosen-select form-control" },
{ "width", "100%" },
{ "data-placeholder", "Select Devices..." }
})
and the jquery function to fill the second dropdown is
function groupSelected(obj) {
var selectedGroupId = obj.options[obj.selectedIndex].value;
$.ajax({
url: "../Devices/DevicesByGroupId",
type: "GET",
dataType: "JSON",
data: { groupId: selectedGroupId },
success: function (devicesData) {
$("#devices").html("");
$.each(devicesData, function (index, itemData) {
$("#devices").append(
$("<option></option>").val(itemData.Value).html(itemData.Text)
);
});
}
});
}
The api method which is being invoked executes and returns data but for some reason, the values are not appended to the second dropdown.
Please suggest what am I missing here.
#StephenMuecke you saved my day mate! Removing the chose-select class loaded the data. I just found that I had to invoke
$("#devices").trigger("chosen:updated");
to update the listbox. Thanks a lot for pointing me in this direction :)

Exporting CSV from ui-grid with cell display rather than the source value

I have a table done with ui-grid and this table has a column with cellFilter definition like this:
{ field: 'company', cellFilter: 'mapCompany:row.grid.appScope.companyCatalog' }
My gridMenu custom item is configured like this:
gridMenuCustomItems: [
{
title:'Custom Export',
action: function ($event) {
var exportData = uiGridExporterService.getData(this.grid, uiGridExporterConstants.ALL, uiGridExporterConstants.ALL, true);
var csvContent = uiGridExporterService.formatAsCsv([], exportData, this.grid.options.exporterCsvColumnSeparator);
uiGridExporterService.downloadFile (this.grid.options.exporterCsvFilename, csvContent, this.grid.options.exporterOlderExcelCompatibility);
},
order:0
}
]
The table is displayed correctly, but when I try to export to CSV, the Company column is exported with empty value. Here is my Plunkr.
Any suggestion will be appretiated
References
I did some research and according to ui-grid Issue #4948 it works good when the Company column is filled with an static catalog. Here is a Plunkr demostrating that.
As you mentioned, there is an export issue when the values in the column are not static, so I forked your plunker with a solution that creates the company mapping for each data object and adds it as a key-value once you get the company catalog back:
$http.get('https://api.github.com/users/hadley/orgs')
.success(function(data) {
$scope.companyCatalog = data;
angular.forEach($scope.gridOptions.data, function(item) {
var compMap = uiGridFactory.getMapCompany(item.company, $scope.companyCatalog);
item.mappedCo = compMap;
});
});
I've kept the original company column but made it invisible (rather than overwriting it), so it exports with the rest of the data in the csv. New column defs:
columnDefs: [
{ field: 'name' },
{ field: 'mappedCo', name: 'Company'},
{ field: 'company', visible: false }
]
Also, in the case that you were getting your data from a server, you would have to ensure that the data and the catalog returned before you run the mapping function. This solution may not work in your particular use case; I don't know.
I found a solution to the CSV export to be able to display the cell display value.
My mistake was using row.grid instead of this.grid at the mapCompany cell filter:
columnDefs: [
{ field: 'name' },
{ field: 'company', cellFilter: 'mapCompany:row.grid.appScope.companyCatalog' }
],
The right way to use it is using this:
columnDefs: [
{ field: 'name' },
{ field: 'company', cellFilter: 'mapCompany:this.grid.appScope.companyCatalog' }
],
Here is my Plunkr.

Handsontable Select2 Dependent Dropdowns

I have two select2 dropdowns and I want to change options the second dropdown depending on first dropdown.
For example,
{
data: 'country_id',
editor: 'select2',
renderer: customDropdownRenderer,
select2Options: {
data: {!! $production_units !!} ,
dropdownAutoWidth: true,
}
},
{
data: 'state_id',
editor: 'select2',
renderer: customDropdownRenderer,
select2Options: {
data: [],
dropdownAutoWidth: true,
width: 'resolve'
}
},
Depending on country_id, I want to change select2 options of state_id. I know how to make this work with just select2, but I am not able to figure out how to make it work with handsontable.
I have change select2Options in afterChange, but how to do that?
afterChange: function (change, source) {
if(change)
{
if(change[0][1] == 'country_id')
{
$.get("/api/states?country="+change[0][3], function(data){
//What should be done here?
});
}
}
},
You retrieve all the states for that country. Make sure the states list is in the same format that select2 expects.
Then loop through the columns list and determine the dependent column for the current column that has been modified.
Get the cell properties:
var cellProperties = instance.getCellMeta(rowIndex, dependentColumnIndex);
Update the select2 source:
cellProperties['select2Options'].data = [states list];

Select2 dropdown but allow new values by user?

I want to have a dropdown with a set of values but also allow the user to "select" a new value not listed there.
I see that select2 supports this if you are using it in tags mode, but is there a way to do it without using tags?
The excellent answer provided by #fmpwizard works for Select2 3.5.2 and below, but it will not work in 4.0.0.
Since very early on (but perhaps not as early as this question), Select2 has supported "tagging": where users can add in their own value if you allow them to. This can be enabled through the tags option, and you can play around with an example in the documentation.
$("select").select2({
tags: true
});
By default, this will create an option that has the same text as the search term that they have entered. You can modify the object that is used if you are looking to mark it in a special way, or create the object remotely once it is selected.
$("select").select2({
tags: true,
createTag: function (params) {
return {
id: params.term,
text: params.term,
newOption: true
}
}
});
In addition to serving as an easy to spot flag on the object passed in through the select2:select event, the extra property also allows you to render the option slightly differently in the result. So if you wanted to visually signal the fact that it is a new option by putting "(new)" next to it, you could do something like this.
$("select").select2({
tags: true,
createTag: function (params) {
return {
id: params.term,
text: params.term,
newOption: true
}
},
templateResult: function (data) {
var $result = $("<span></span>");
$result.text(data.text);
if (data.newOption) {
$result.append(" <em>(new)</em>");
}
return $result;
}
});
For version 4+ check this answer below by Kevin Brown
In Select2 3.5.2 and below, you can use something like:
$(selector).select2({
minimumInputLength:1,
"ajax": {
data:function (term, page) {
return { term:term, page:page };
},
dataType:"json",
quietMillis:100,
results: function (data, page) {
return {results: data.results};
},
"url": url
},
id: function(object) {
return object.text;
},
//Allow manually entered text in drop down.
createSearchChoice:function(term, data) {
if ( $(data).filter( function() {
return this.text.localeCompare(term)===0;
}).length===0) {
return {id:term, text:term};
}
},
});
(taken from an answer on the select2 mailing list, but cannot find the link now)
Just for the sake of keep the code alive, I'm posting #rrauenza Fiddle's code from his comment.
HTML
<input type='hidden' id='tags' style='width:300px'/>
jQuery
$("#tags").select2({
createSearchChoice:function(term, data) {
if ($(data).filter(function() {
return this.text.localeCompare(term)===0;
}).length===0)
{return {id:term, text:term};}
},
multiple: false,
data: [{id: 0, text: 'story'},{id: 1, text: 'bug'},{id: 2, text: 'task'}]
});
Since many of these answers don't work in 4.0+, if you are using ajax, you could have the server add the new value as an option. So it would work like this:
User searches for value (which makes ajax request to server)
If value found great, return the option. If not just have the server append that option like this: [{"text":" my NEW option)","id":"0"}]
When the form is submitted just check to see if that option is in the db and if not create it before saving.
There is a better solution I think now
simply set tagging to true on the select options ?
tags: true
from https://select2.org/tagging
Improvent on #fmpwizard answer:
//Allow manually entered text in drop down.
createSearchChoice:function(term, data) {
if ( $(data).filter( function() {
return term.localeCompare(this.text)===0; //even if the this.text is undefined it works
}).length===0) {
return {id:term, text:term};
}
},
//solution to this error: Uncaught TypeError: Cannot read property 'localeCompare' of undefined
Thanks for the help guys, I used the code below within Codeigniter I I am using version: 3.5.2 of select2.
var results = [];
var location_url = <?php echo json_encode(site_url('job/location')); ?>;
$('.location_select').select2({
ajax: {
url: location_url,
dataType: 'json',
quietMillis: 100,
data: function (term) {
return {
term: term
};
},
results: function (data) {
results = [];
$.each(data, function(index, item){
results.push({
id: item.location_id,
text: item.location_name
});
});
return {
results: results
};
}
},
//Allow manually entered text in drop down.
createSearchChoice:function(term, results) {
if ($(results).filter( function() {
return term.localeCompare(this.text)===0;
}).length===0) {
return {id:term, text:term + ' [New]'};
}
},
});
I just stumbled upon this from Kevin Brown.
https://stackoverflow.com/a/30019966/112680
All you have to do for v4.0.6 is use tags: true parameter.
var text = 'New York Mills';
var term = 'new york mills';
return text.localeCompare(term)===0;
In most cases we need to compare values with insensitive register. And this code will return false, which will lead to the creation of duplicate records in the database. Moreover String.prototype.localeCompare () is not supported by browser Safary and this code will not work in this browser;
return this.text.localeCompare(term)===0;
will better replace to
return this.text.toLowerCase() === term.toLowerCase();

Resources