knockout validation for array of objects - validation

I have an array of dynamically added objects and I want to validate this array for required fields and numeric values.
I have 3 buttons, one for adding note, another for removing note and one for saving
How to validate every object ?
.. the code:
$(function () {
var initialData = [{
Title: "",
NoteText: "",
Suggestion: "",
MediaTime: ""
}];
var CreateNewNoteModel = function (Notes) {
var self = this;
self.Notes = ko.observableArray(ko.utils.arrayMap(Notes, function (Note) {
return { Title: Note.Title, NoteText: Note.NoteText, Suggestion: Note.Suggestion, MediaTime: Note.MediaTime };};
}));
var i = 1;
self.addNote = function () {
self.Notes.push({
Title: "", NoteText: "", Suggestion: "", MediaTime: ""
});
$('#editor' + i).wysihtml5();
$('#editorB' + i).wysihtml5();
i++;
};
self.removeNote = function (Note) {
self.Notes.remove(Note);
};
self.save = function () {
self.lastSavedJson(JSON.stringify(ko.toJS(self.Notes), null, 2));
var jsondata = self.lastSavedJson();
$.ajax({
url: "/api/Notes/?mid=" + m + "&p=" + p,
cache: false,
type: 'Post',
dataType: 'json',
contentType: 'application/json; charset=utf-8',
data: jsondata,
success: function () {
alert("Success");
document.location.reload(true);
}
});
};
self.lastSavedJson = ko.observable("")
};
ko.applyBindings(new CreateNewNoteModel(initialData));
});

I am using jQuery validate plugin to add validation to knockout-js by using jQuery's validation methods: "$.validator.addMethod" and "$.validator.addClassRules".
Example:
First define your validation methods and css classes. Later on, we add the css classes to your inputs to validate your fields.
function DefineValidationRules() {
$.validator.addMethod("validateNumber", ValidateInteger, "This field is not a number");
$.validator.addMethod("validateRequired", $.validator.methods.required, "This field is required");
$.validator.addMethod("validateMin", $.validator.methods.min, $.format("This number be greater than or equal to {0}"));
$.validator.addMethod("validateMax", $.validator.methods.min, $.format("This number must be less than or equal to {0}"));
$.validator.addMethod("validateMinlength", $.validator.methods.minlength, $.format("This field must contain at least {0} characters"));
$.validator.addMethod("validateRangelength", $.validator.methods.rangelength, $.format("This field must contain between {0} and {1} characters"));
$.validator.addClassRules("validate-number", { validateNumber: true });
$.validator.addClassRules("validate-number-min", { validateNumber: true, validateMin: 1 });
$.validator.addClassRules("validate-required-number-min", { validateRequired: true, validateNumber: true, validateMin: 1 });
$.validator.addClassRules("validate-required", { validateRequired: true });
$.validator.addClassRules("validate-rangelengthmax6", { validateRangelength: [0,6] });
}
DefineValidationRules();
You can also add your own custom validation method:
function ValidateInteger(value) {
//do whatever you want to check
}
Having an input in knockout:
<input class="validate-required validate-number" type="text" data-bind="value: examplefield, valueUpdate: 'afterkeydown', attr: { attrname: 'itsvalue'}" />
Checking on submit:
$("#yoursubmitbutton").on("click", function () {
var formtosubmit = $("#idofyourform");
//check for validation errors
if (isValid(formtosubmit)) {
formtosubmit.submit();
//
// code to proceed to next step
}
});
function isValid(el) {
var $thisform = el;
$thisform.validate({
errorElement: "label",
errorPlacement: function (error, element) {
//eventual different error placing
if (element.attr("name") == "fname" || element.attr("name") == "lname") {
element.css("border", "2px solid red");
error.insertAfter("#lastname");
} else {
error.insertAfter(element);
}
}
});
return $thisform.valid();
}

Related

select2 ajax dynamic search multipleselect - set values from respons on document ready

I have problem with passing data to select2 (ajax dynamic search) in edit mode on document ready.
I create test button which should add data on click and it doesnt work... Any ideas with that?
$('.select2').select2({
minimumInputLength: 3,
ajax: {
url: (...),
dataType: 'json',
data: function (params) {
return {
query: params.term
};
},
processResults: function (data, params) {
var resData = [];
data.forEach(function (value) {
if (value.name.toLowerCase().indexOf(params.term.toLowerCase()) != -1)
resData.push(value)
})
return {
results: $.map(resData, function (item) {
return {
text: item.name,
slug: item.slug,
id: item.id
}
})
};
},
},
});
$('#preselectObjectDataButton').on('click', function() {
var _array = []
var o = new Object;
o.id = 1;
o.text = "test";
o.slug = "test";
_array.push(o);
$('.select2').val(_array).trigger('change.select2');
});

Telerik Kendo MVC Grid Validation Always Fails

I am tearing my hair out with this...!
I have a telerik kendo mvc ui grid widget using an Inline gridedit mode. When the user adds a new entry to the grid (by way of a custom dropdown edit control), I want it to validate that this entry is not already present in the grid.
I have an MVC controller action that does this and returns True or False accordingly. This works perfectly. Here is the validator javascript code I am using.
(function ($, kendo) {
$.extend(true, kendo.ui.validator, {
rules: {
bedQuantity: function (input, params) {
if (input.is("[name='Quantity']") && input.val() <= 0) {
input.attr("data-bedQuantity-msg", "Quantity must be 1 or more");
return false;
}
return true;
},
bedExists: function(input, params) {
if (input.is("[name='BedType']")) {
var model = {
PropertyId: #Model.Id,
BedTypeId: input.val()
};
var url = "/Property/ValidateBedTypeExists";
input.attr("data-val-bedExists-requested", true);
$.ajax({
type: "POST",
url: url,
traditional: true,
data: JSON.stringify(model),
contentType: "application/json; charset=utf-8",
success: function(data) {
return data === false;
},
fail: function(data) {
return false;
}
});
} else {
return true;
}
}
},
messages: {
bedQuantity: function (input) {
return input.attr("data-val-bedQuantity");
},
bedExists: function(input) {
return "This bed type already exists";
}
}
});
})(jQuery, kendo);
No matter whether the ajax call returns true or false, the validator always flags the entry as invalid.
You can give the html attribute for the kendoDropdownList as required like this
#(Html.Kendo().DropDownList()
.DataValueField("")
.DataTextField("")
.Name("")
.HtmlAttributes(new { required ="required" })
.OptionLabel("- Select a type - ")
.Filter(FilterType.Contains)
)
Try this..

Kendo Treeview expand and checkbox not working after new value was passed in from a dropdown list

new to stackoverflow and implementing treeview. I'm having an issue where whenever I select a different value from my dropdown list that would populate my treeview the expand and checkbox is not working anymore. But the first time works.
So I have ajax call that would grab a parameter from a dropdown list to return JSON data to populate my tree. Here's my code. I've been pounding my head for this error and I've also tried some solution in the kendo ui documentation but it just doesn't work. Really need some help. Thank you!
Here's my code:
dataB1 = #Html.Raw(Json.Encode(ViewData["branchList"]));
reloadNewBranch = #Html.Raw(Json.Encode(ViewData["reloadNewBranch"]));
$('#comboNewBranch').kendoAutoComplete({
dataSource: dataB2,
placeholder: "Enter branch name...",
value: reloadNewBranch
});
//Create TreeView
function onChange(e) {
$("body").css("cursor", "progress");
$('#hiddenPackageArray').val('');
document.getElementById("textTestpassId").innerHTML = 'At least one(1) template must be selected.';
$('#treeview').empty();
$.ajax({
url: '#Url.Action("LoadOldBranchTemplates", "Home")',
data: { oldBranchName: $("#comboOldBranch").data("kendoAutoComplete").value() },
dataType: "json"
}).done(function (result, textStatus, jqXHR) {
var viewModel = new kendo.data.HierarchicalDataSource({
data: result,
schema: {
model: {
id: "Id",
hasChildren: true,
children: "Templates"
}
}
});
$("#treeview").kendoTreeView({
loadOnDemand: false,
checkboxes: {
checkChildren: true
},
check: onCheck,
dataSource: viewModel,
dataTextField: ["TestPassName", "DisplayName"]
})
// gathers IDs of checked nodes
function checkedNodeIds(nodes, checkedNodes) {
for (let i = 0; i < nodes.length; i++) {
if (nodes[i].checked) {
checkedNodes.push(nodes[i].Id);
let filtered = checkedNodes.filter(function (listOfId) {
return listOfId != null;
});
$('#hiddenPackageArray').val(filtered);
}
if (nodes[i].hasChildren) {
checkedNodeIds(nodes[i].children.view(), checkedNodes);
}
}
}
// show checked node IDs on datasource change
function onCheck(e) {
console.log("I'm in onSelect function");
var checkedNodes = Array();
var treeView = $("#treeview").data("kendoTreeView");
var message = String();
checkedNodeIds(treeView.dataSource.view(), checkedNodes);
console.log("Checkbox changed :: " + this.text(e.node));
if (checkedNodes.length > 0) {
message = checkedNodes.join(" ");
} else {
message = "No package(s) are selected.";
$('#hiddenPackageArray').val('');
}
$("#result").html(message);
}
$("body").css("cursor", "default");
})
.fail(function (xmlHttpRequest, textStatus, errorThrown) {
$('#mainDiv').append('<p>Status: ' + textStatus + '</p>');
$('#mainDiv').append('<p>Error: ' + errorThrown + '</p>');
$('#mainDiv').append('<p>' + xmlHttpRequest + '</p>');
});
};

keep the Ids of selected results of Kendo UI Autocomplete in a hidden input

I wrote this code to use kendo UI autocomplete. I need to show the title of the selected result in the textbox and keep the if in some hidden input, how can I get the id. it seems the select doesn't work.
$("[data-autocomplete]").each(function () {
var luurl = $(this).attr('data-lookupurl');
var thisElemt = $(this);
$(this).kendoAutoComplete({
minLength: 3,
separator: ", ",
dataTextField: "title",
select: function (e) {
var selectedOne = this.dataItem(e.item.Index());
console.log(kendo.stringify(selectedOne));
},
dataSource: new kendo.data.DataSource({
serverFiltering: true,
serverPaging: true,
pageSize: 20,
transport: {
read: luurl,
dataType: "json",
parameterMap: function (data) {
return { title: thisElemt.val() };
},
schema: {
model: {
id: "id",
fields: {
id: { type: "id" },
title: { type: "string" }
}
}
}
}
})
});
});
There is a typo error, you should use: e.item.index() instead of e.item.Index() (index is lowercase).
So the select function would be:
select : function (e) {
var selectedOne = this.dataItem(e.item.index());
console.log(kendo.stringify(selectedOne));
},
and easier way is :
var autocomplete = $("#autoCompleteId").data("kendoAutoComplete");
console.log(autocomplete.listView._dataItems[0]);
you can access to select data item in autocomplete.listView._dataItems[0] object
you can use script
<script>
$(document).ready(function () {
$("#categories").change(function () {
var url = '#Url.Content("~/")' + "Limitations/ThanaByDistrict_SelectedState";
var ddlsource = "#categories";
var ddltarget = "#target";
$.getJSON(url, { Sel_StateName: $(ddlsource).val() }, function (data) {
$(ddltarget).empty();
$(ddltarget).val(data);
});
});
});
</script>
in controller like
// Get selected combox value
public JsonResult ThanaByDistrict_SelectedState ( Guid Sel_StateName )
{
JsonResult result = new JsonResult ( );
objects temp=db . objects . Single ( m => m . ob_guid == Sel_StateName );
result . Data = temp.ob_code;
result . JsonRequestBehavior = JsonRequestBehavior . AllowGet;
return result;
}
For details you can see this LINK

How to dynamically change event sources?

I am using the jQuery FullCalendar plug-in. I want to load initially the calendar with events as an array. I am doing this like:
events: <%= Model.Events %>
or
eventSources: [{
events: <%= Model.Events %>
}]
Both ways work fine. I am using MVC 3.0 and <%= Model.Events %> returns an array of events in JSON format.
I want to use the events array ONLY for the initial loading of the calendar. Later, every times events are needed to be fetched, I want my events to be loaded using the url '/Calendar/Events'.
How can be this implemented?
I tried difference scenarios with addEventSource/removeEventSource in the viewDisplay callback, but nothing worked fine for me.
.fullCalendar( {
eventSources : [ {
url : '/Calendar/Events',
type : 'GET'
} ],
viewDisplay : function( event ) {
// assuming this will point to the full calendar,
// might have to do something silly like
// $( '#myCal' ).fullCalendar( 'refetchEvents' );
this.refetchEvents();
}
} );
I know it's a very old question but I needed this right now. The answer wasn't here but I found it in another question.
Here what is solution.
My primary source of events is this(this is the events source from the default examples of Fullcalendar):
events: function(start, end, callback) {
$.ajax({
type: 'POST',
url: 'myurl',
dataType:'xml',
crossDomain: true,
data: {
// our hypothetical feed requires UNIX timestamps
start: Math.round(start.getTime() / 1000),
end: Math.round(end.getTime() / 1000),
'acc':'2',
},
success: function(doc) {
var events = [];
var allday = null; //Workaround
var Editable = null; //Workaround
$(doc).find('event').each(function()
{
if($(this).attr('allDay') == "false") //Workaround
allday = false; //Workaround
if($(this).attr('allDay') == "true") //Workaround
allday = true; //Workaround
if($(this).attr('editable') == "false") //Workaround
Editable = false; //Workaround
if($(this).attr('editable') == "true") //Workaround
Editable = true; //Workaround
events.push({
id: $(this).attr('id'),
title: $(this).attr('title'),
start: $(this).attr('start'),
end: $(this).attr('end'),
allDay: allday,
editable: Editable
});
});
//calendar.fullCalendar( 'addEventSource', othersources.folgas );
//calendar.fullCalendar( 'addEventSource', othersources.ferias );
//calendar.fullCalendar('refetchEvents');
callback(events);
}
});
}
Now i needed it to add more sources and to do this ouside the calendar (next to the date variables from fullcalendar examples) i made a variable like the code above, but with ajax calls similar to my primary: )
var othersources = {
anothersource: {
events: function(start, end, callback) {
$.ajax({
type: 'POST',
url: 'myurl',
data: {
// our hypothetical feed requires UNIX timestamps
start: Math.round(start.getTime() / 1000),
end: Math.round(end.getTime() / 1000),
'acc':'7',
},
success: function(doc) {
var events = [];
var allday = null; //Workaround
var Editable = null; //Workaround
$(doc).find('event').each(function()
{
if($(this).attr('allDay') == "false") //Workaround
allday = false; //Workaround
if($(this).attr('allDay') == "true") //Workaround
allday = true; //Workaround
if($(this).attr('editable') == "false") //Workaround
Editable = false; //Workaround
if($(this).attr('editable') == "true") //Workaround
Editable = true; //Workaround
events.push({
id: $(this).attr('id'),
title: $(this).attr('title'),
start: $(this).attr('start'),
end: $(this).attr('end'),
allDay: allday,
editable: Editable
});
});
callback(events); //notice this
}
});
},
cache: true,
//error: function() { alert('something broke with courses...'); },
color: 'green', //events color and stuff
textColor: 'white',
//className: 'course'
}
}
Now, he build diffrent sources and use like this both...
eventSources: [ othersources.anothersource ],
viewDisplay: function(view) {
if (view.name == 'month'){
calendar.fullCalendar( 'addEventSource', othersources.anothersource );
//calendar.fullCalendar('refetchEvents');
//Notice i'm not doing the refetch events. And its working for me. but i'm calling thi elsewhere, every time i make an action. So you must figure it out ;)
}
Link to above solution
And another way i found on github.
Basically the problem was that I can't change data parameters after calendar initialization. For events this worked:
events: {
url : '',
type: 'POST',
data: function () {
return {
action: 'view',
search_text: search_text
};
},
error: function() {
alert('there was an error while fetching events!');
},
color: '#31b0d5', // a non-ajax option
textColor: '#fff;', // a non-ajax option
},
for resources it didnt so I had to make like that:
resources: function(callback) {
var view = $("#calendar").fullCalendar("getView");
$.ajax({
url: "",
type: 'POST',
dataType: "json",
cache: false,
data: {
start : view.start.format(),
end : view.end.format(),
timezone : view.options.timezone,
action : 'projects_employees',
search_text: search_text
}
}).then(function(resources) {
callback(resources);
})
},
Simple ways like that do not work cuz are static and couldn't be changed after init:
events: {
url: '',
type: 'POST',
data: {
action: 'view',
search_text: search_text
}
},
resources: {
url: '',
type: 'POST',
data: {
action: 'projects_employees',
search_text: search_text
}
}
Here is the github link. Replied by peon501.
After to many try, i did solve my problem with use first part (stackoverflow) codes. The key for me defiying eventSource with "var" key and use it like this
//...
eventSources: [ othersources.anothersource ] ,
//...
I have collected all the data in a php file the way I want it. And the output of this page was a javascript with this
header('Content-Type: text/javascript');
$fromDB ="";
$sources = "sources = [";
foreach ($events as $value) { // value is source name
$fromDB .= "var $value = {
url: path + 'fetchEvents.php',
method: 'GET',
extraParams: {
value: $value,
code: new URLSearchParams(window.location.search).get('code'),
},
failure: function(error) {
console.log(error);
Swal.fire('Error!', '', 'error');
},
};
";
$sources .= $value. " ";
}
$sources .= " ];";
// this $sources give me
// sources = [anothersource ,othersource ,anothersource2 ];
This make like this
var anothersource = {
url: path + 'fetchEvents.php',
method: 'GET',
extraParams: {
value: $value,
code: new URLSearchParams(window.location.search).get('code'),
},
failure: function(error) {
console.log(error);
Swal.fire('Error!', '', 'error');
},
};
var othersource = {
url: path + 'fetchEvents.php',
method: 'GET',
extraParams: {
value: $value,
code: new URLSearchParams(window.location.search).get('code'),
},
failure: function(error) {
console.log(error);
Swal.fire('Error!', '', 'error');
},
};
var anothersource2 = {
url: path + 'fetchEvents.php',
method: 'GET',
extraParams: {
value: $value,
code: new URLSearchParams(window.location.search).get('code'),
},
failure: function(error) {
console.log(error);
Swal.fire('Error!', '', 'error');
},
};
sources = [anothersource ,othersource ,anothersource2 ];
.fullCalendar( {
eventSources : sources , // here, we use dynamic eventsources
viewDisplay : function( event ) {
// assuming this will point to the full calendar,
// might have to do something silly like
// $( '#myCal' ).fullCalendar( 'refetchEvents' );
this.refetchEvents();
}
} );
I added the main javascript file, which will do all the operations, at the bottom of this php file.
//...
$file = "my/fullcalender/initjavascript/file.js"
file_get_contents($file) . PHP_EOL;
//...
This code opens the javascript file in the $file path and takes whatever is in it and adds it to this file.
I hope that will be useful.

Resources