Remote Validation with Knockout in MVC 4, Allowing invalid data to save - asp.net-mvc

Hi there I am using remote validation with knockout validation rules to check if a client is booked at the same time as the proposed date. I finally got the viewmodel sending data to the controller validation method and the method does return a true or false however i began to notice that the call back was not stopping the user from saving if the client is not valid.
I found this by swapping the conditions and allowing the controller method to return false I debugged the client side and found that the call back variable was in fact false but i was not receiving an error messae nor was it stopping m from saving the appointment.
My question is am i missing a piece of code that allows this or is there a bug that i am missing?
Viewmodel rule validation:
ko.validation.rules['validateClientasync'] = {
async: true,
message: 'Client is already booked in at this time!',
validator: function (val, parms, callback) {
var defaults = {
url: '/Appointments/CheckClient/',
type: 'POST',
contentType: 'application/x-www-form-urlencoded',
success: function (data) {
callback(/* true or false depending on what you get back in data */);
}
};
if (parms.data != undefined && parms.data.appointment != undefined) {
var appointment = ko.toJS(parms.data.appointment);
$.ajax({
url: '/Appointments/CheckClient/',
type: 'post',
contentType: 'application/x-www-form-urlencoded',
data: ko.toJS(parms.data.appointment),
success: function(data) {
callback(/* true or false depending on what you get back in data */);
}
});
}
}
};
ko.validation.registerExtenders();
self.appointment = {
id: appointment.id,
start: ko.observable(appointment.start),
end: ko.observable(appointment.end),
text: ko.observable(appointment.text),
clientid: ko.observable(appointment.clientid).extend({
validateClientasync: {
data: self
}
}),
employeeid: ko.observable(appointment.employeeid),
roomid: ko.observable(appointment.roomid),
fee: ko.observable(appointment.fee).extend({min: 10})
};

according to the definition in https://github.com/Knockout-Contrib/Knockout-Validation/wiki/Async-Rules, just put a json there would be enough, like:
callback(
{
isValid: true //true or false with json format returned from the validation method in your controller,
message: "your cusotm error message here"
}
);

Related

Passing FormCollection and FormData to controller [duplicate]

This question already has answers here:
How to append whole set of model to formdata and obtain it in MVC
(4 answers)
Closed 7 years ago.
$("#btn2").click(function () {
var data = new FormData();
var Form = $("#form2").serialize();
var send = {FormData+&+ data};
$.ajax({
url: '#Url.Action("AddProduct", "Product")',
data: send,
cache: false,
contentType: false,
processData: false
});
});
How to send FormData and Form object through ajax, please check the code its not working but it will tell you what I want to achieve
And also please mention how to receive this in Controller.
Basically I want to send picture and formcollection to my controller
Thanks
$("#btn2").click(function () {
var data = new FormData($('.form').get(0));
$.ajax({
url: '#Url.Action("AddProduct", "Product")',
type: 'POST',
data: data,
cache: false,
contentType: false,
processData: false
});
});
Through googling I got this code but my controller still receiving null??
Controller
public void AddProduct(Product product, HttpPostedFileBase myImage){}
You can use form.serialize to send data to your controller.
$(document).ready( function() {
var form = $('#form2');
$.ajax( {
type: "POST",
url: form.attr( 'action' ),
data: form.serialize(),
success: function( response ) {
console.log( response );
}
} );
} );

Ajax not allowing View rendering

I have a couple of variations on the ajax depending on the flow of interactions on the page. But it's only the variables that changes. here is one of them:
$('#btn_skickaEnkel').bind('click', function () {
$.ajax({
type: 'POST',
url: '/Contact/IntresseAnmälan/',
dataType: 'json',
data: {
Namn: $('#namn').val(),
Mail: $('#mail').val(),
Info: $('#meddelande').val(),
Nivå: $('#nivå').find(":selected").text(),
IsEnkel: true,
Telefon: $('#nr').val(),
ID: function () {
var url = window.location.pathname;
var id = url.substring(url.lastIndexOf('/') + 1);
return id;
}
},
traditional: true
});
});
In my controller i am unable to redirect or return a different view. At this point the data from JSON is no longer relevant because it's already been saved to DB.
My Controller:
public ActionResult IntresseAnmälan(BokningContainer bokning)
{
db = new DbContext();
//Saving some data to database(removed)
//Just determening the state of container obj.
if (bokning.IsEnkel)
{
//Geting som information from db (removed)
//Creating a mail (removed)
email.Send(bokning.Namn, bokning.Mail, body);
}
else
{
}
//db.SaveChanges();
//This part is not working, I think it's beacuase of the Ajax
return View("IntresseAnmälan");
}
The view is not rendered and I think it's related to the ajax. The view is simply not rendered. Is there some way to force returning it and ignoring the ajax? As I said the data is no longer needed because the content is already saved to the DB.
You cannot render view on ajax call,simply you can use form post method or just redirect it to desired action on "succcess" of ajax call as below:
$('#btn_skickaEnkel').bind('click', function () {
$.ajax({
type: 'POST',
url: '/Contact/IntresseAnmälan/',
dataType: 'json',
data: {
Namn: $('#namn').val(),
Mail: $('#mail').val(),
Info: $('#meddelande').val(),
Nivå: $('#nivå').find(":selected").text(),
IsEnkel: true,
Telefon: $('#nr').val(),
ID: function () {
var url = window.location.pathname;
var id = url.substring(url.lastIndexOf('/') + 1);
return id;
}
},
traditional: true,
success: function(result) {
window.location.href = '#Url.Action("action", "Controller")';
}
});
});
I couldn't believe my eyes when I figured out this "Bugg". The problem was that I, at some point, changed the submit to a button. So the form was never submiting. Well, at least I learnt a bit about views and Ajax.
Sorry for taking your time.

Kendo UI - Specify parameter name on dataSource read

With Kendo UI, I am using an autocomplete box to try and retrieve data from my server. It is hitting an ASP.NET MVC controller with the following signature.
public ActionResult aspect(string term){
// ...
}
This means that the request needs to have the correct parameter in the url. Now the issue I am running into is that I cannot discover a way to specify this in the dataSource mechanics. I have read the documentation on parameterMap dozens of times and it makes absolutely no sense to me in any way.
This is complicated further by the fact that the page in question actually has 10-15 autocomplete text boxes at any one time, each dynamically created with dynamic identity.
The code I am using so far is as follows;
$(".autocomplete").kendoAutoComplete({
dataTextField: "Name",
dataSource: {
type: "json",
transport: {
read: {
url: "/search/aspect"
}
}
}
});
So is there anything I can do to tell it how to name the parameter it passes?
To make it more clear what I am trying to do, if I were doing this in jQuery, I would use ...
$.ajax({ url: '/search/aspects', data: { term: (insert the data here) } });
But because of the way all of this works, there is no set "selector" to get the autocomplete input, so I cannot retrieve its value from the input form element.
First, enable server-side filtering by setting this option:
dataSource: {
serverFiltering: true,
Then the value is passed as one of the parameters into the transport.parameterMap function.
If you were to log the object passed in to the parameterMap function like this:
$(".autocomplete").kendoAutoComplete({
dataTextField: "Name",
dataSource: {
serverFiltering: true,
type: "json",
transport: {
read: {
url: "/search/aspect"
},
parameterMap: function (data, action) {
console.log(data);
}
}
}
});
then you would get an object that looks like this:
{
"filter":{
"logic":"and",
"filters":[
{
"value":"something",
"operator":"contains",
"field":"Name",
"ignoreCase":true
}
]
}
}
So you can use this to get the value entered into the AutoComplete box by doing:
$(".autocomplete").kendoAutoComplete({
dataTextField: "Name",
dataSource: {
serverFiltering: true,
type: "json",
transport: {
read: {
url: "/search/aspect"
},
parameterMap: function (data, action) {
if(action === "read") {
return {
term: data.filter.filters[0].value
};
} else {
return data;
}
}
}
}
});
I think that there is a misunderstanding about the relation between DataSource and AutoComplete. AutoComplete has the input and uses a DataSource for retrieving the data: the input does not belong to the AutoComplete and as consequence you cannot get the input that is using a DataSource from a method that is from the DataSource (as transport.read.data or transport.parameterMap).
You need to unique identify which element has the input and the value that it contains.
What I do propose is getting the value using document.activeElement.value. Since you are typing it, the element that has the focus should be the element that you are using.
The code would be:
$(".autocomplete").kendoAutoComplete({
dataTextField: "Name",
dataSource: {
type: "json",
transport: {
read: {
url: "/search/aspect",
},
parameterMap : function (data, type) {
if (type === "read") {
return { term : document.activeElement.value }
}
}
}
}
})
Alternatively, you can enable serverFiltering and then Kendo UI links the input field with the filtering condition. The code would be:
$(".autocomplete").kendoAutoComplete({
dataTextField: "Name",
dataSource : {
serverFiltering: true,
type : "json",
transport : {
read : {
url : "/search/aspect"
},
parameterMap: function (data, type) {
if (type === "read") {
return { term : data.filter.filters[0].value }
}
}
}
}
});
I'm a little confused as to what you're wanting to do. If you are just trying to pass the string term to the controller you can specify the data:
$(".autocomplete").kendoAutoComplete({
dataTextField: "Name",
dataSource: {
type: "json",
transport: {
read: {
url: "/search/aspect",
data: { term: "value" }
}
}
}
})
Thanks for the clarification and help OnaBai. Here is the code that I got working after hours of frustration!
$("#contractsSearchField").kendoComboBox({
dataTextField: "name",
dataValueField: "id",
autoBind: false,
placeholder:'select...',
filter: "contains",// a filter must be present for the datasources serverFiltering argument to work properly.
minLength: 3,
dataSource: new kendo.data.DataSource({
serverFiltering: true,//We must turn on serverFiltering and sorting, otherwise, the combobox only works once and will not change it's values.
serverSorting: true,
group: { field: "searchtype" },
transport: {
read: {
url: "contract.cfc?method=getContractForDropdown",
// We are not passing the data here like we do in the autosuggest. The combobox is a different type of an animal.
dataType: "json",
contentType: "application/json; charset=utf-8", // Note: when posting json via the request body to a coldfusion page, we must use this content type or we will get a 'IllegalArgumentException' on the ColdFusion processing page.
type: "GET"
},//read
// Pass the search term that was typed in by the user. This works because when the user types into the input box, it becomes that active element in the form.
parameterMap : function (data, type) {
if (type === "read") {
return { searchTerm : document.activeElement.value }
//return { searchTerm: data.filter.filters[0].value }
}
}//parameterMap
}//transport
})//dataSource
}); //...kendoComboBox...

ExtJS4.1: Why model.save() sends wrong thing to server?

I tried to use model.save() to POST a new user. But I check request payload and found that it not only sent the data, but also sent other parts of the model. That makes my server cannot parse the payload.
The request payload generated :
{"phantom":true,"internalId":"ext-record-58","raw":{},"data":{"userId":0,"userName":"Amy"},"modified":{"userName":""},"hasListeners":{},"events":{},"stores":[],"dirty":true,"id":"AM.model.User-ext-record-58"}
But the desired request payload should be :
{"userId":0,"userName":"Amy"}
And I am aware that the "phantom" of my model is false before I call model.save(). But it becomes true in the request payload. Is it a clue?
Model:
Ext.define('AM.model.User',{
extend: 'Ext.data.Model',
fields: [
{ name: 'userId', type: 'int' },
{ name: 'userName', type: 'string' },
{ name: 'createdTime', type: 'string' },
],
idProperty: 'userId',
associations: [
{
type: 'hasOne',
model: 'AM.model.ModelA',
name:'modelA',
associationKey:'modelA',
getterName:'modelA'
},
{
type: 'hasOne',
model: 'AM.model.ModelB',
name:'modelB',
associationKey:'modelB',
getterName:'modelB'
}
],
proxy: {
type: 'rest',
success:true,
url:'../restful/users',
writer:{
type:'json',
getRecordData:function(record){ //parse createdTime to the format Y-m-d
record.set('createdTime', Ext.Date.format(new Date(record.get('createdTime')), "Y-m-d"));
return record;
}
},
reader: {
type: 'json'
}
}
});
This is the view which has the data to be posted. The view will fill the data to the model:
Ext.define('AM.view.UserRegisterForm',{
extend:'Ext.form.Panel.',
alias:'widget.userRegisterForm',
fields:new Array(), //I want to render the fields in xtemplate, so instead of adding the fields to items, I use an array to manage them.
retrieveData(model){
model.set('userName', this.fields[0].getValue());
model.set('createdTime',this.fields[1].getValue());
}
}
The function in the controller, which sends the POST request:
postUser:function(){
var userRegisterForm= this.getUserRegisterForm();
var userModel = this.getUserModel();
var user= new userModel();
var me = this;
userRegisterForm.retrieveFieldData(user);
console.log(user); //the data in console looks fine!
user.save({
success: function(response) {
//do something...
},failure:function(response) {
alert('fail');
}
});
}
You are returning the full record when you override getRecordData Where as you are just meant to return the records data. record.getData()
Some extra advice. Don't override getRecordData to set the models creation date. Use the models defaultValue property to give assign it a new Date if one doesn't exist.

jquery response back

I am sending an ajax call to another page. I want to get a value of a variable, lets call it x, back from that page on success. How can I do that. here is my ajax code
$.ajax({
type: 'POST',
url: 'myotherpage.php',
data: 'loginname=' + loginname ,
success: function(success) {
if(success == 1) {
//get the variable value here
} else {
//do nothing
}
}
});
Your other page should return json, which contains a status variable (1 for success, 0 for fail), and the variable or whatever data you need. Here's an example from a file I have here. It won't run of course, but should give you the idea.
Req = $.ajax({
type: 'POST',
data: this.data.filter,
url: this.data.DataURL+"listids",
dataType: 'json',
timeout: 5000,
cache: false,
error: function(){
UserNotify({class:'notify_alert', content:'Your request can\'t be completed at this time.<br />An external error has been encountered. Please wait a moment and try again.'});
},
success: function(o){
if ( 0==o.status ) {
if ( undefined == o.user_msg ) { o.user_msg = '';}
UserNotify({class:'notify_alert', content:'Your request can\'t be completed at this time.<br />'+o.user_msg});
} else {
if ( 0 < o.data.ids.length ) {
tli.data.update.ids = o.data.ids;
}
}
}
});
echo out the variable in your php file instead of "1" and have it return null when something is wrong.
$.ajax({
type: 'POST',
url: 'myotherpage.php',
data: 'loginname=' + loginname ,
success: function(success) {
if(success == '') {
// error alert
alert('Something went wrong. Reload the page and try again.');
} else {
alert(success); // alert the value from what you printed out in myotherpage.php
}
}
});
I don't know what you are trying to do but to give you an idea,
if(success == 1) {
// codes get executed here if myotherpage.php would display 1
// so I'm wondering how would you create a variable there...
// if you put anything other than just '1' in myotherpage.php, codes inside this "if" will not be excuted
//get the variable value here
} else {
//do nothing
}
in this,
success: function(data) {...} // "data" is the data being returned from the server

Resources