У нас есть сетка Kendo, в которой у нас есть обязательная проверка поля в первом столбце сетки. Работает нормально, но позиция сообщения всегда идет сверху, даже если я работаю над самой последней строкой сетки.
<style>
/* Including these styles to undo styles found elsewhere, especially in responsiveStyle.css */
.k-dropdown, .k-datepicker {
margin-bottom: 0px !important;
margin-top: 0px !important;
}
.k-numeric-wrap input[type=text] {
margin-top: 0px
}
.kendo-form-controls .k-autocomplete, .kendo-form-controls .k-colorpicker, .kendo-form-controls .k-combobox, .kendo-form-controls .k-datepicker, .k-datetimepicker, .kendo-form-controls .k-dropdown, .kendo-form-controls .k-numerictextbox, .kendo-form-controls .k-selectbox, .kendo-form-controls .k-textbox, .kendo-form-controls .k-timepicker, .kendo-form-controls .k-toolbar .k-split-button {
margin-bottom: 0px;
}
</style>
<link href="~/Content/css/Locations/kendocommonui.css" rel="stylesheet" />
<div class="panel panel-default form-horizontal">
<header class="panel-heading">
<h1 class="panel-Message">
<span>@CommonResourceFile.PersonMessagesPageMessage</span>
</h1>
</header>
<div class="button-container col-sm-12">
@if (Model.IsEdit)
{
<input id="AddNewRecordButton" class="jqButton f_rt margin-bottom5" type="button" value='@CommonResourceFile.PersonMessagesButtonAddText' onclick="javascript: AddPersonMessage();" />
}
</div>
<div class="clear clear-div-height"></div>
<div class="panel-body form-horizontal kendo-form-controls">
@if (Model.IsView || Model.IsEdit)
{
<div class="clear"></div>
<div id="PersonMessagesGridContainer" class="marginRight-AddressInfo">
<div id="PersonMessagesGrid"></div>
<style>
/*Type ahead does not automatically space like drop down for some reason.*/
.clear-div-height {
height: 14px;
}
.k-grid-content {
min-height: 250px !important;
}
.reason-validation-error-box {
margin-left: 167px !important;
}
.k-pager-wrap .k-dropdown {
width: 60px; /* specify the width */
}
</style>
<script>
const gridSelector = "#PersonMessagesGrid";
function kendoGrid() {
return $(gridSelector).data("kendoGrid");
}
function AddPersonMessage() {
kendoGrid().addRow();
}
// Loading data for drop down lists.
var Companys = @Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject(Model.Companys) as String);
var PersonMessageTypes = @Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject(Model.PersonMessageTypes) as String);
var currentTypes = @Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject(Model.Currents) as String);
var isVisibleTypes = @Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject(Model.Visibles) as String);
var canEdit = @Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject(Model.IsEdit) as String);
if (!Companys || !(Companys instanceof Array) || Companys.length === 0) {
console.warn('No Companys Types have been defined for this country system.');
//ShowMessage('No Companys have been defined for this country system.');
}
if (!PersonMessageTypes || !PersonMessageTypes.length) {
console.warn('No Person Message Types have been defined for this country system.');
}
// Default values
const CompanyDefaultId = GetDefaultValue(Companys);
const PersonMessageTypeDefaultId = GetDefaultValue(PersonMessageTypes);
const isCurrentDefaultValue = GetDefaultValue(currentTypes);
const isVisibleDefaultValue = GetDefaultValue(isVisibleTypes);
var makeValidatorHook = fieldName => $(`<span class="k-invalid-msg" data-for="${fieldName}"></span>`);
$(document).ready(function () {
const NO_VALIDATION_ERROR = true;
const VALIDATION_ERROR_FOUND = false;
let myBaseUrl = '@myApiBaseUrl'
let readUrl = '@Url.Action("GetPersonMessages", "Person")' + '?PersonId=' +@Model.PersonId;
let updateUrl = '@Url.Action("UpdatePersonMessage", "Person")';
let createUrl = '@Url.Action("SavePersonMessage", "Person")';
let destroyUrl = '@Url.Action("DeletePersonMessage", "Person")';
let commands = [];
if (canEdit) {
commands =
[
{
name: "edit",
visible: function (dataItem) { return canEdit; }
},
{
name: "Delete",
click: function (e) {
e.preventDefault(); // prevent page scroll reset
var tr = $(e.target).closest("tr");
var data = this.dataItem(tr);
data.CreatedDate = null;
data.ModifiedDate = null;
data.BeginDate = null;
data.EndDate = null;
let callBackOuter = callBackResult => {
if (callBackResult) {
let dataSource = PersonMessagesGrid.data().kendoGrid.dataSource;
dataSource.remove(data) // prepare a "destroy" request
dataSource.sync() // actually send the request (might be ommited if the autoSync option is enabled in the dataSource)
}
};
ConfirmationDialog(`Confirm Deletion`, `Are you sure you want to delete the ${data.Message}?`, callBackOuter)
}
}
];
}
let PersonMessagesGrid = $(gridSelector).kendoGrid({
dataSource: {
schema: {
model: {
id: "PersonMessageId",
fields: {
PersonMessageId: { type: "number", editable: false, nullable: true, defaultValue: 0 },
PersonId: { type: "number", editable: false, nullable: false, defaultValue: @Model.PersonId },
DataSourceId: { type: "number", editable: false, nullable: false, defaultValue: 78 },
Message: {
type: "string",
editable: true,
validation: {
MessageValidation: function (input) {
let name = input.attr('name');
if (name !== 'Message') {
return NO_VALIDATION_ERROR;
}
let Message = $.trim(input.val());
if (!Message) {
input.attr("data-MessageValidation-msg", "Message is required");
return VALIDATION_ERROR_FOUND;
}
if (Message.length > 200) {
input.attr("data-MessageValidation-msg", "Message cannot exceed 200 characters");
return VALIDATION_ERROR_FOUND;
}
return NO_VALIDATION_ERROR;
}
}
},
BeginDate: {
type: "date",
editable: true,
nullable: true
},
EndDate: {
type: "date",
editable: true,
nullable: true
},
PersonMessageTypeId: {
type: "number",
editable: true,
validation: { min: 0, required: false },
defaultValue: null
},
CompanyId: {
type: "number",
editable: true,
validation: { min: 0, required: false },
defaultValue: null
}
}= data: function (response) {
if (response) {
if (response.Data) {
return response.Data;
}
}
return response;
},
total: function (response) {
if (response) {
if (response.Data) {
return response.Data.length;
}
return response.length;
}
}
},
transport: {
read: {
url: readUrl,
type: 'GET'
}
,update: {
url: updateUrl,
type: 'PUT',
dataType: "json"
},
destroy: {
url: destroyUrl,
type: 'DELETE'
},
create: {
url: createUrl,
type: 'POST'
}
},
pageSize: 20,
sort: { field: "Message", dir: "asc"},
error: function (e) {
console.error('GRID DATASOURCE ERROR:');
console.error(e);
},
requestEnd: function (e) {
console.log(`Server request ended type was ${e.type}`);
if (e.type === "read") {
} else
if (e.type === "create" || e.type === "update" || e.type === "destroy") {
if (e.response.Errors != null && e.response.Errors.Error != null &&
e.response.Errors.Error != null && e.response.Errors.Error.errors[0] != null) {
console.warn(`error: ${e.response.Errors.Error.errors[0]}`);
//displayErrorDialog(e.response.Errors.Error.errors[0]);
if (e.type === "update" && (e.response.Errors.Error.errors[0] === "Please select an Company")) {
$(gridSelector).data('kendoGrid').dataSource.read();
}
}
else if (e.response && e.response.Errors && Object.values(e.response.Errors).length) {
let errorMessage = Object.values(e.response.Errors)[0].errors[0];
//displayErrorDialog(errorMessage);
if (e.type === "update" && (errorMessage === "Please select an Company")) {
$(gridSelector).data('kendoGrid').dataSource.read();
}
}
//else if (e.response.Result != "Success") {
// ShowMessage(e.response.Result);
//}
}
} // End of function requestEnd(..)
}, // End of DataSource
filterable: {
extra: false,
operators: {
string: {
eq: "Is Equal To",
contains: "Contains"
}
}
},
sortable: true,
pageable: {
refresh: true,
pageSizes: true,
buttonCount: 5
}
,columns: [
{
Message: "@CommonResourceFile.PersonMessagesColumnMessage",
field: "Message",
width: 180
},
{
Message: "Message Type",
field: "GetValueForDropDownListColumn(PersonMessageTypes,'PersonMessageTypeId','MessageTypeName')",
template: "<div>#: GetTextFromValue(PersonMessageTypes,PersonMessageTypeId, 'PersonMessageTypeId','MessageTypeName') #</div>",
editor: makeMessageTypeDropDownListEditor(PersonMessageTypes),
width: 200,
filterable: {
extra: false,
operators: {
string: {
eq: 'Is Equal To'
}
},
ui: MessageTypeFilter
}
},
{
Message: "@CommonResourceFile.PersonMessagesColumnInstitution",
field: "InstitutionName",
width: 180
},
{
Message: "@CommonResourceFile.PersonMessagesColumnCompany",
field: "GetValueForDropDownListColumn(Companys,'CompanyId','CompanyName')",
template: "<div>#: GetTextFromValue(Companys,CompanyId,'CompanyId','CompanyName') #</div>",
editor: makeCompanyDropDownListEditor(Companys),
width: 200,
filterable: {
extra: false,
operators: {
string: {
eq: 'Is Equal To',
isempty: 'Empty'
}
},
ui: CompanyFilter
}
},
{
Message: "@CommonResourceFile.PersonMessagesColumnStart",
field: "BeginDate",
width: 140,
format: "{0:MM/dd/yyyy}",
},
{
Message: "@CommonResourceFile.PersonMessagesColumnEnd",
field: "EndDate",
width: 140,
format: "{0:MM/dd/yyyy}"
},
{
Message: "@CommonResourceFile.PersonMessagesColumnSequence",
field: "SequenceNumber",
width: 120,
editor: makeIntegerEditor()
},
{
Message: canEdit ? "Action" : "",
command: commands,
width: 170,
hidden: canEdit === false
}
],
detailTemplate: kendo.template($("#PersonMessagesDetailTemplate").html()),
editable: "inline",
edit: onGridEdit,
save: function (e) {
// Do nothing here.
},
error: function (e) {
console.error('GRID ERROR:');
console.error(e);
}
}); // End of KendoGrid definition
// Generic code snippet that correctly disables sorting and filtering when a grid is in edit mode.
$(".k-grid").on("mousedown", ".k-grid-header th", function (e) {
// prevent sorting/filtering for the current Grid only
var grid = $(this).closest(".k-grid");
var editRow = grid.find(".k-grid-edit-row");
// prevent sorting/filtering while any Grid is being edited
//var editRow = $(".k-grid-edit-row");
if (editRow.length > 0) {
alert("Please complete the editing operation before sorting or filtering");
e.preventDefault();
}
});
let addButton = _ => $("#AddNewRecordButton");
let disableControl = control => control.prop("disabled", true).addClass("k-state-disabled");
let enableControl = control => control.prop("disabled", false).removeClass("k-state-disabled");
let collapseAllRows = kendoGridObject => kendoGridObject.tbody.find('.k-master-row').each(function () { kendoGridObject.collapseRow(this); });
function onGridEdit(e) {
let kendoGridObject = this;
let model = e.model;
const NEW_RECORD = model.isNew();
// Collapse all rows
collapseAllRows(kendoGridObject);
//kendoGridObject.tbody.find('.k-master-row').each(function () { kendoGridObject.collapseRow(this); });
e.container.find("input[name='Message']").attr('maxlength', '200');
e.container.find("input[name='InstitutionName']").attr('maxlength', '200');
e.container.find("input[name='ExternalCode']").attr('maxlength', '50');
let parent = e.container.parent();
const KENDO_UPDATE_BUTTON = 'k-grid-update';
const KENDO_UPDATE_BUTTON_MARKER = 'k-grid-update-button';
let updateButton = parent.find(`.${KENDO_UPDATE_BUTTON}`).addClass(KENDO_UPDATE_BUTTON_MARKER);
updateButton = parent.find(`.${KENDO_UPDATE_BUTTON_MARKER}`);
let enableUpdateButton = () => updateButton.addClass(KENDO_UPDATE_BUTTON);
let disableUpdateButton = () => updateButton.removeClass(KENDO_UPDATE_BUTTON);
disableControl(addButton());
disableUpdateButton();
let updateButtonText = model.isNew() ? "Save" : "Update";
let cancelButton = parent.find(".k-grid-cancel");
updateButton.removeClass("hide-imp").html(`<span class="k-icon k-update"></span>${updateButtonText}`);
cancelButton.removeClass("hide-imp");
// Get handle on master row.
let masterRow = e.container.closest(".k-master-row");
// Expand detail template of current row
// WARNING: The view/edit templates do not exist before the following line:
kendoGridObject.expandRow(masterRow);
// Detail section with view/edit templates exists only after expander is clicked. It is injected into the DOM after the current master row.
let detailRow = masterRow.next();
let viewTemplate = detailRow.find("#viewTemplate");
let editTemplate = detailRow.find("#editTemplate");
// Fix this: JACK
$('#IsVisible').val(e.model.IsVisible).attr("selected", "selected");
viewTemplate.hide();
editTemplate.show();
kendo.bind(editTemplate, e.model);
// Fix this: JACK
if (e.model.IsVisible === "" || e.model.IsVisible === null) {
$('#IsVisible').val("true").attr("selected", "selected");
}
// Bind cancel button event
updateButton.bind("click", function (element) {
element.preventDefault(); // prevent page scroll reset
enableUpdateButton();
enableControl(addButton());
var createdDateString = kendo.toString(kendo.date.today(), "MM-dd-yyyy h:mm:ss tt");
e.model.BeginDate = kendo.toString(e.model.BeginDate, "MM/dd/yyyy");
e.model.EndDate = kendo.toString(e.model.EndDate, "MM/dd/yyyy");
e.model.CreatedDate = createdDateString;
e.model.ModifiedDate = createdDateString;
});
cancelButton.bind("click", function () {
kendoGridObject.expandRow(masterRow);
viewTemplate.show();
editTemplate.hide();
kendo.unbind(editTemplate, e.model);
enableControl(addButton());
});
} // End of OnGridEdit
}); // document ready
</script>
</div>
}
else
{
<b>@CommonResourceFile.ViewPermissionDenied</b>
}
</div>
</div>
<script id="PersonMessagesDetailTemplate" type="text/kendo-tmpl">
<style>
.label-vertical-align {
/*padding-top: 7px;*/
padding-top: 0px;
}
.text-vertical_align {
padding-top: 7px;
}
.text-break {
word-break: break-word;
}
.template-label {
padding-right: 0px;
}
.textbox-vertical-spacer {
height: 10px;
}
</style>
Не могли бы вы подсказать, что здесь не так, подсказка о проверке должна отображаться точно так же строка, над которой я сейчас работаю