Hello I am new to AngularJS and I am trying to populate values for my column dropdown in a ui grid. Currently it just displays undefined for the whole list.
Here is my column definition:
{ field: "FullName", displayName: "Employee", editableCellTemplate: 'ui-grid/dropdownEditor', validators: { required: true }, minWidth: 150, width: "25%", cellFilter: 'mapEmployee', editDropdownIdLabel: 'Value', editDropdownValueLabel: 'Text', editDropdownOptionsArray: dataService.getEmployees() },
Here is my service function:
function getEmployees() {
return $.ajax({
url: '/EmployeeSkills/GetEmployees',
type: 'POST',
dataType: "json",
success: getEmployeesComplete,
error: getEmployeesFailed
});
function getEmployeesComplete(r) {
return r;
}
function getEmployeesFailed(e) {
$log.warn("Failed to get employees. " + e.data);
return $q.reject(e);
}
}
Here is my Controller method:
[HttpPost]
public JsonResult GetEmployees()
{
try
{
List<string> tecPosition = new List<string>() { "SUB", "" };
IEnumerable<SelectListItem> Employees = db.Employees.Where(x => tecPosition.Contains(x.JobPosition) && x.Active).Select(c => new SelectListItem
{
Value = c.EmployeeNumber.ToString(),
Text = c.FullName
});
return Json(new SelectList(Employees), JsonRequestBehavior.AllowGet);
}
catch (Exception e)
{
return null;
}
}
Here is my ui grid:
<div class="row">
<div class="grid" ui-grid="gridOptions"
ui-grid-pagination
ui-grid-selection
ui-grid-edit
ui-grid-row-edit
ui-grid-validate
ui-grid-exporter
ui-grid-cellNav
style="height: 500px;">
</div>
</div>
Any help would be greatly appreciated. It does make it to my Controller method and appears to be working but in the display it just list undefined over and over. Thanks
I had to add a cellFilter of griddropdown:editDropdownOptionsArray:editDropdownIdLabel:editDropdownValueLabel:row.entity.employees.fullname. And write a filter to map the value to the id when the cell loses focus.
.filter('griddropdown', function () {
return function (input, map, idField, valueField, initial) {
if (typeof map !== "undefined") {
for (var i = 0; i < map.length; i++) {
if (map[i][idField] == input) {
return map[i][valueField];
}
}
} else if (initial) {
return initial;
}
return input;
};
Related
I have a panel where I take data from a view in database, and show them. The data are being showed but it is being replicated 3 times, I mean, each row apears 3 times in my table (panel).
When I use my filters, the data apears only one time though, as it should be.
I thought that I was calling my function "criarDataTables()" 3 times, but this is not the case.
This is in my Index.cshtml:
#section Scripts{
#Scripts.Render("~/bundles/typeahead")
#Scripts.Render("~/bundles/datatables")
#Scripts.Render("~/Scripts/js/bootstrap-datapicker.js")
#Scripts.Render("~/Scripts/js/bootstrap-datepicker.pt-BR.js")
#Scripts.Render("~/Scripts/jQuery-Mask/jquery.mask.min.js")
<script type="text/javascript">
var tbPainelTriagem;
var reload = false;
function criarDataTables() {
tbPainelTriagem = $("#tb-triagem").DataTable({
searching: false,
processing: true,
serverSide: true,
ajax: {
url: "/PainelTriagem/ListaPainelTriagem",
type: "POST",
data: {
customSearch: {
[...]
}
}
},
columns: [
{ data: "ID_VIEW" },
{ data: "TIPO" },
[...]
],
columnDefs: [
],
drawCallback: function (settings, json) {
$("#frm-filtro :input").prop("disabled", false);
}
});
}
$(document).ready(function () {
var listaDs;
$('#dsUnidIntField').attr("autocomplete", "off");
$('#dsUnidIntField').typeahead({
name: 'resultDs',
limit: 200,
minLength: 0,
source: function (query, process) {
itens = [];
listaDs = {};
$.post('/PainelTriagem/DsAutocomplete', { query: query }, function (data) {
$.each(data, function (i, item) {
listaDs[item.Nome] = item;
itens.push(item.Nome);
});
process(itens);
});
},
updater: function (item) {
var ds = listaDs[item];
$('#ID_VIEW', '#frm-filtro').val(ds);
return ds.Nome;
}
});
criarDataTables();
})
</script>
}
[...]
<table id="tb-triagem" class="table table-striped table-bordered dataTableLayout">
<thead>
<tr>
<th>ID View</th>
<th>Tipo</th>
[...]
</tr>
</thead>
</table>
This is in my PainelTriagemController.cs
using [...]
namespace PainelMV.Controllers
{
public class PainelTriagemController : Controller
{
[...]
[HttpPost]
public ActionResult ListaPainelTriagem(HCDataTableRequest<PainelTriagem> dataTableRequest)
{
try
{
HCDataTableResponse<PainelTriagemViewModel> dataTable = MyPainelTriagemManager
.ToList(dataTableRequest).CastViewModel(x => new PainelTriagemViewModel
{
ID_VIEW = x.ID_VIEW,
TIPO = x.TIPO == null ? " - " : x.TIPO.ToString(),
[...]
});
return Json(dataTable);
}
catch(Exception ex)
{
return Json(new { success = false, message = ex.Message });
}
}
}
}
And this is in my PainelTriagemStore.cs
using [...]
namespace PainelMV.Data.Store
{
public class PainelTriagemStore : BaseStore<PainelTriagem, AppContext>
{
public PainelTriagemStore(AppContext context): base(context) { }
public HCDataTableResponse<PainelTriagem> ToList(HCDataTableRequest<PainelTriagem> dataTableRequest)
{
try
{
HCDataTableResponse<PainelTriagem> response = new HCDataTableResponse<PainelTriagem>();
var qr = _context.PainelTriagem.AsQueryable();
response.recordsTotal = qr.Count();
int? tipo = dataTableRequest.GetCustomSearchInt("tipo");
string nmPaciente = dataTableRequest.GetCustomSearchString("nmPaciente");
[...]
if (tipo != null)
{
qr = qr.Where(x => x.TIPO == tipo);
}
[...]
response.recordsFiltered = qr.Count();
qr = qr.OrderAndPaging(dataTableRequest);
response.data = qr.ToList();
return response;
}
catch(Exception ex)
{
throw ex;
}
}
}
}
I have the same problem with this one Why ui grid value drop-down box will be assigned in the event fires before beginCellEdit in angular
And have little bit difference. After I updated the editDropdownOptionArray it still keep the old value, It's only have the new value in the next click.
Hope everyone can help me with this one.
Thank you.
Here is my code snippet:
The html of the dropdown:
<div>
<form name="inputForm">
<select ng-class="'colt' + col.uid"
ui-grid-edit-dropdown
ng-model="MODEL_COL_FIELD"
ng-options="field CUSTOM_FILTERS for field in editDropdownOptionsArray"></select>
</form>
</div>
The controller code:
$scope.menuColumns = [
{ displayName: 'Menu', field: 'name', enableCellEdit: false },
{
displayName: 'Access Level', field: 'accessLevelName',
editableCellTemplate: 'Scripts/application/role/directive/dropdown-menu-assignment.html',
editDropdownValueLabel: 'Access Level', editDropdownOptionsArray: userMgtConstant.menuAccessLevel
}
];
$scope.menuOptions = {
data: [],
onRegisterApi: function (gridApi) {
gridApi.edit.on.beginCellEdit($scope, function (rowEntity, colDef, event) {
if (rowEntity.parent === true) {
colDef.editDropdownOptionsArray = $scope.levelList;
} else {
colDef.editDropdownOptionsArray = $scope.childLevelList;
}
});
gridApi.edit.on.afterCellEdit($scope, function (rowEntity, colDef, newValue, oldValue) {
if (rowEntity.parent !== true) {
if(rowEntity.name === 'Revenue Bench'){
var accessLevel = commonUtils.getIdFromName(rowEntity.accessLevelName, userMgtConstant.menuAccessLevel);
if(accessLevel > 1){
$scope.isShowFunctionAssignment = false;
} else if(rowEntity.functionAssignments.length !== 0) {
$scope.isShowFunctionAssignment = true;
}
}
} else {
// udpate child dropdown list menu
var index = _(userMgtConstant.menuAccessLevel).indexOf(newValue);
$scope.childLevelList = $scope.levelList.filter(function (item, i) {
return i >= index;
});
if($scope.childLevelList.length > 2){
parentSwitch = true;
}
if($scope.childLevelList.length < 3 && parentSwitch){
colDef.editDropdownOptionsArray = $scope.childLevelList;
parentSwitch = false;
}
// update all child value
_($scope.menuOptions.data).each(function (dataItem) {
if (dataItem.parent !== true) { // prevent infinite loop
dataItem.accessLevelName = newValue;
}
});
}
});
}
};
Here is the usage of the grid:
<inline-edit-grid options="menuOptions" columns="menuColumns"></inline-edit-grid>
You should look into the usage of editDropdownRowEntityOptionsArrayPath instead of editDropdownOptionsArray
From the docs :
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
Ok, here are the Versions:
Kendo UI v2014.3.1119
AngularJS v1.3.6
jQuery v#1.8.1 jquery.com
The issue is the following: I have a kendo upload that should populate a grid after a excel file is read. I'm using Kendo UI Angular Directives. Here are some key pieces of code:
Upload Html
<input name="files"
type="file"
kendo-upload
k-async="{ saveUrl: '{{dialogOptions.ImportUrl}}', autoUpload: false, batch: true }"
k-options="{localization: {uploadSelectedFiles: '{{messages.Global_Button_Import}}'}}"
k-error="onImportError"
k-select="onSelect"
k-success="onImportSuccess" k-multiple="false" />
Grid Html
<div kendo-grid="grid" k-options="gridOptions" k-ng-delay="gridOptions" k-rebind="gridOptions" >
</div>
Key pieces on the controller
angular.module('global').controller('ImportResultsController', [
'$scope', 'BaseApi', 'ImportResultsService', 'GridUtil', '$http', '$q', '$timeout',
function ($scope, BaseApi, ImportResultsService, GridUtil, $http, $q, $timeout) {
$scope.gridOptions;
$scope.gridColumns;
$scope.results = new kendo.data.ObservableArray([]);
//These columns should come from the server, right now are harcoded
$scope.getGridColumns = function () {
$scope.gridColumns = [
{ field: "Zone", width: 70, title: "Zone", template: "" },
{ field: "Aisle", width: 70, title: "Aisle", template: "" },
{ field: "Rack", width: 70, title: "Rack", template: "" },
{ field: "Shelf", width: 70, title: "Shelf", template: "" },
{ field: "Bin", width: 70, title: "Bin", template: "" },
//{ field: "DateEffectiveFrom", width: 70, title: "Date" },
{ field: "BinStatus", width: 70, title: "BinStatus", template: "" }
];
}
$scope.getClientGridOptions = function(columns, data, pageSize) {
var gridOptions = {
sortable: true,
dataSource: {
data: data,
pageSize: pageSize
},
selectable: 'row',
columns: columns,
pageable: {
pageSize: pageSize,
refresh: false,
pageSizes: [10, 20, 30],
messages: $.kendoMessages
},
};
return gridOptions
}
$scope.onImportSuccess = function (e) {
var files = e.files;
if (e.operation == "upload") {
console.log(files);
if (e.XMLHttpRequest.response != "") {
var model = $.parseJSON(e.XMLHttpRequest.response); //This step does not fail, model return is always filled
$scope.results = new kendo.data.ObservableArray([]);
for (var i = 0; i < model.Data.length; i++) {
$scope.results.push(model.Data[i]);
}
$scope.gridOptions = $scope.getClientGridOptions($scope.gridColumns, $scope.results, 10);
//$scope.grid.dataSource.data($scope.results); //This does not work
$scope.isDataReady = true;
// $("#grid").data("kendoGrid").dataSource.data($scope.results) //This does not work
// $scope.grid.refresh(); //This does not work
$scope.$apply()
}
}
}
}]);
The issues vary. Sometimes I get the data bound until the second uploaded file, and after the third time, I start receiving 'Cannot read property 'get' of undefined ' errors. When this second error happens, the bind works, but the error is present. Do you have any idea of what could it be?
In case of you need the url for the upload, here's the method. Is an MVC .net application. Since I always get the response correctly and it's a Json Array, I believe there's no issue there, but here's anyways.
dialogOptions.ImportUrl = LoadImportedBinLocations
MVC Controller
[System.Web.Http.HttpPost]
public ActionResult LoadImportedBinLocations(IEnumerable<HttpPostedFileBase> files)
{
bool success = false;
var importHistory = new PartsImportHistory();
List<dynamic> data = null;
try
{
//int divisor = 0;
//var y = 5 / divisor;
if (files != null)
{
using (var client = new ServiceLocator<IPartsService>())
{
foreach (var file in files)
{
string extension = Path.GetExtension(file.FileName);
bool isExcelFile = extension == ".xls" || extension == ".xlsx";
if (isExcelFile)
{
var filePath = UploadAttachment(file);
//importHistory = client.Service.SavePartsImportHistory(new PartsImportHistory
//{
// CreatedByName = CurrentContext.UserDisplayName,
// CreatedByUserID = CurrentContext.UserId,
// PartsImportStatus = (int)DMSModel.EnumStore.PartsImportStatus.InProgress,
// FilePath = filePath
//});
data = new List<dynamic>
{
new { Zone = "A", Aisle = "02", Rack = "06", Shelf = "20", Bin = "D", DateEffectiveFrom = DateTime.UtcNow, BinStatus = "Unblocked", IsValid= true, ImportError ="" },
new { Zone = "B", Aisle = "02", Rack = "06", Shelf = "10", Bin = "D", DateEffectiveFrom = DateTime.UtcNow, BinStatus = "Blocked", IsValid=false, ImportError="Zone does not Exist" }
};
success = true;
}
else
{
throw new Exception(WarpDMS.Globalization.Resources.PartsAdmin_ImportParts_ErrorFileFormat);
}
}
}
}
return Json(new { success = success, Data = data });
}
catch (Exception ex)
{
return Content(ex.Message ?? ex.ToString());
}
}
private string UploadAttachment(HttpPostedFileBase item)
{
string path = string.Empty;
string internalFileName = string.Empty;
string basePath = ConfigManager.ATTACHMENTS_PATH;
if (item != null && item.ContentLength > 0)
{
internalFileName = System.IO.Path.ChangeExtension(Guid.NewGuid().ToString(), System.IO.Path.GetExtension(item.FileName));
path = Path.Combine(basePath, internalFileName);
item.SaveAs(path);
}
return Path.Combine(basePath, internalFileName).Replace('\\', '/');
}
I am using the latest version of JTable from http://jtable.org/ (downloaded it yesterday). I setup my JTable as shown below (I also included the server-side code below, which is written in C#). The List function works (the data shows up in the table), the Add function works, and the Delete function works. However, when I go to Edit a row, there is an error when trying to populate the data for the "ElevationsMulti" field. I get an error that simply says, "Cannot load options for field ElevationsMulti."
JTable Code:
$('#ReportsContainer').jtable({
title: 'Reports',
actions: {
listAction: '/Report_SingleEstimate/GetReportNames?customerId=' + customerId,
createAction: '/Report_SingleEstimate/AddReport',
updateAction: '/Report_SingleEstimate/EditReport',
deleteAction: '/Report_SingleEstimate/DeleteReport'
},
fields: {
ReportID: {
key: true,
list: false
},
ReportName: {
title: 'Report Name'
},
CustomerID: {
title: 'Customer',
list: false,
options: '/Estimates/GetCustomers',
defaultValue: customerId
},
PlanNameID: {
title: 'Plan Name',
dependsOn: 'CustomerID',
options: function (data) {
if (data.source == 'list') {
return '/Estimates/GetListOfPlanNames?customerId=0';
}
//data.source == 'edit' || data.source == 'create'
return '/Estimates/GetListOfPlanNames?customerId=' + data.dependedValues.CustomerID;
}
},
ProductID: {
title: 'Product',
options: '/Estimates/GetProducts'
},
HeaderFieldsMulti: {
title: 'Fields',
options: '/Report_SingleEstimate/GetHeaderFields',
type: 'multiselectddl',
list: false
},
ElevationsMulti: {
title: 'Elevations',
type: 'multiselectddl',
dependsOn: ['PlanNameID', 'ProductID'],
options: function (data) {
if (data.source == 'list') {
return '/Elevation/GetAllElevations';
}
return '/Report_SingleEstimate/GetElevations?PlanNameID=' + data.dependedValues.PlanNameID +
'&ProductID=' + data.dependedValues.ProductID;
},
list: false
}
}
});
$('#ReportsContainer').jtable('load');
Not sure if it makes a difference in JTable, but the ElevationsMulti depends on the PlanNameID and ProductID fields, and the PlanNameID field depends on the CustomerID fields. In other words, the ElevationsMulti field depends on a field that depends on another field (multiple nested dropdowns).
C# server-side code:
[HttpPost]
public JsonResult GetElevations(int PlanNameID, int ProductID)
{
try
{
int estimateId = Estimates.getEstimateId(PlanNameID, ProductID);
List<MyDropdownList> elevations = Estimate_ElevationList.listElevationsByEstimateForDropdown(estimateId);
return Json(new { Result = "OK", Options = elevations });
}
catch (Exception ex)
{
return Json(new { Result = "ERROR", Message = ex.Message });
}
}
Error here:
Further debugging has given me a more specific error.
The parameters dictionary contains a null entry for parameter 'PlanNameID' of non-nullable type 'System.Int32' for method 'System.Web.Mvc.JsonResult GetElevations(Int32, Int32)' in 's84.Controllers.Report_SingleEstimateController'. An optional parameter must be a reference type, a nullable type, or be declared as an optional parameter.
Basically, JTable sends PlanNameID to the server as a null value. Which seems to indicate that JTable has not loaded the options for the PlanNameID field yet when it makes the server call for the ElevationsMulti field.
How do I make JTable wait to load the ElevationsMulti field until after the PlanNameID field has been loaded?
Problem solved.
The problem came from using the Type "multiselectddl" in JTable. I changed the code in JTable that creates the multiselectddl to the same code as the regular dropdown. Here is the code:
_createInputForRecordField: function (funcParams) {
...
//Create input according to field type
if (field.type == 'date') {
return this._createDateInputForField(field, fieldName, value);
} else if (field.type == 'textarea') {
return this._createTextAreaForField(field, fieldName, value);
} else if (field.type == 'password') {
return this._createPasswordInputForField(field, fieldName, value);
} else if (field.type == 'checkbox') {
return this._createCheckboxForField(field, fieldName, value);
} else if (field.options) {
if (field.type == 'multiselectddl') {
return this._createDropDownListMultiForField(field, fieldName, value, record, formType, form);
} else if (field.type == 'radiobutton') {
return this._createRadioButtonListForField(field, fieldName, value, record, formType);
} else {
return this._createDropDownListForField(field, fieldName, value, record, formType, form);
}
} else {
return this._createTextInputForField(field, fieldName, value);
}
},
_createDropDownListMultiForField: function (field, fieldName, value, record, source, form) {
//Create a container div
var $containerDiv = $('<div class="jtable-input jtable-multi-dropdown-input"></div>');
//Create multi-select element
var $select = $('<select multiple="multiple" class="' + field.inputClass + '" id="Edit-' + fieldName + '" name=' + fieldName + '></select>')
.appendTo($containerDiv);
var options = this._getOptionsForField(fieldName, {
record: record,
source: source,
form: form,
dependedValues: this._createDependedValuesUsingForm(form, field.dependsOn)
});
this._fillDropDownListWithOptions($select, options, value);
return $containerDiv;
}
Im new to YUI3; Im trying to poll a datasource every 10 seconds to refresh a datatable. But with the code below it says there is 'No Data To Display'... Sorry for the large amount of code...
YUI().use("datatable", "datasource-get", "datasource-jsonschema", "datatable-datasource", "datasource-polling", "datasource-function", function (Y) {
var url = "http://query.yahooapis.com/v1/public/yql?format=json" +
"&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys",
query = "&q=" + encodeURIComponent(
'select * from local.search ' +
'where zip = "94089" and query = "pizza"'),
dataSource,
table;
dataSource = new Y.DataSource.Get({ source: url });
dataSource.plug(Y.Plugin.DataSourceJSONSchema, {
schema: {
resultListLocator: "query.results.Result",
resultFields: [
"Title",
"Phone",
{
key: "Rating",
locator: "Rating.AverageRating",
parser: function (val) {
// YQL is returning "NaN" for unrated restaurants
return isNaN(val) ? -1 : +val;
}
}
]
}
});
intervalId = dataSource.setInterval(10000, {
request : query,
callback: {
success: function (e) {
table.datasource.load(e.response);
},
failure: function (e) {
}
}
});
table = new Y.DataTable({
columns: [
"Title",
"Phone",
{
key: "Rating",
formatter: function (o) {
if (o.value === -1) {
o.value = '(none)';
}
}
}
],
summary: "Pizza places near 98089",
caption: "Table with JSON data from YQL"
});
table.plug(Y.Plugin.DataTableDataSource, { datasource: dataSource });
// This line works (but it doesnt poll)
//table.datasource.load({ request: query });
table.render("#pizza");
});
The line I am not sure about is...
success: function (e) {
table.datasource.load(e.response);
},
The following should fit your needs: http://developer.yahoo.com/yui/examples/datatable/dt_polling.html