I'm trying to store user input in a javascript array and send it to controller via ajax call. But all I get in controller's parameter is null.
Here's the code:
<table class="table-condensed table-bordered table-striped table-responsive">
#foreach (var project in projects)
{
<tr>
#foreach (var parameter in parameters)
{
<td>
<input type="text" class="form-control remar" id=#i />
</td>
i++;
}
</tr>
}
<tr>
<td colspan=#(parameters.Count() + 1)>
<button class="btn btn-primary pull-right" onclick="insert()">Submit Remarks</button>
</td>
</tr>
</table>
<script>
function insert() {
var remarks = [];
jQuery(".remark").each(function () {
remarks.push(jQuery(this).val());
});
$.ajax({
type: "POST",
url: "#Url.Action("AddRemarksToEvaluationSheet", "Teacher")",
data: JSON.stringify({ function_param: remarks }),
contentType: "application/json; charset=utf-8;"
});
}
</script>
Controller:
public ActionResult AddRemarksToEvaluationSheet(string[] function_param)
{
return View();
}
Any help?
P.S. the above code is edited. It worked!
You've got lots going on here...
First, don't give your input boxes ids of numbers - in this scenario, it doesn't look like you even use the value...But if you need it, put the value into a data element:
<input type="text" class="form-control remark" data-remark-id="#i" />
When retrieving the values, you need to get the value, not the textbox itself:
var remarks = [];
jQuery(".remark").each(function() {
remarks.push(jQuery(this).val());
});
When doing anything weird with parameters, like arrays or complex objects, if you use JSON instead of the default of URL-encoded, it will make things nicer.
You should also avoid absolute paths, and use Url.Action instead, so that it'll work regardless of where your app lives relative to the domain.
$.ajax({
type: "POST",
url: "#Url.Action("AddRemarksToEvaluationSheet", "Teacher")",
data: JSON.stringify({ function_param: remarks }),
contentType: "application/json; charset=utf-8;"
});
And you can accept an array of strings, rather than of objects:
[HttpPost]
public ActionResult AddRemarksToEvaluationSheet(string[] function_param)
{
}
I have a feeling that you aren't getting the remarks in the array in the first place.
If you aren't already, use a browser that allows you to debug the js. If you use Chrome, right-click -> inpsect element (or F12). Go to the 'Sources' tab, go to your js file and put a break point to see what the remarks array looks like.
Regarding the code:
You do not seem to need id attributes on the inputs. Let alone numerical ids.
To populate the remarks array, get all dom elements having the class you placed on all inputs. For each one, push the value in the array.
var remarks = [];
$(".form-control").each(function() {
remarks.push($(this).val());
});
You can add extra code to only add the ones with value.
var remarks = [];
$(".form-control").each(function() {
if($(this).val().length){
remarks.push($(this).val());
}
});
The ajax call:
$.ajax({
type: "POST",
url: addRemarksUrl,
data: JSON.stringify({ function_param: remarks }),
contentType: "application/json; charset=utf-8;"
});
Where addRemarksUrl can be a global variable declared in the html.
There are other ways of getting the url. Have a look here:
How to send razor created Url to js file
This user offers 3 possible solutions:
global js variable
custom "data-" attribute
hidden input
Related
i am very new to ASP.NET MVC and trying to make a project tracking tool.
i want to show a list of Questions from a table when page loads and it works.
but when a user click on the "Select Category Name" he should get all Questions as above and a check mark on the Questions which are related to specific category.as of now i am filtering and getting only the filtered Questions which is correct but the list should show all other categories questions as unchecked.
i have a table for Questions, Category and a one to many relationship between both of them hence i made a mapping table named QuestionCategoryMapping Table.
the problem i am facing that i don't know how to filter first all the questions and then later put a checkbox when a user select from list.
i have made two separate functions both are working but i need the separated functionality together.
here are my code spinets.
// test code for partial view in project
QuestionDataAccessLayer questionDataAccessLayer = new QuestionDataAccessLayer();
//controller to add a partial view in create and edit question page
public new PartialViewResult PartialView()
{
IEnumerable<Questions> questions = questionDataAccessLayer.GetAllQuestion();
return PartialView("Partial_View", questions);
}
QuestionCategoryDataAccessLayer questionCategoryDataAccess = new QuestionCategoryDataAccessLayer();
public new PartialViewResult PartialView1(int id)
{
IEnumerable<QuestionCategory> questionCategory = questionCategoryDataAccess.GetQuestionsPerCategory(id);
return PartialView("Partial_View1", questionCategory);
}
the JavaScript,HTML files are as below:
<script>
// code to update the partial view
window.onload = function () {
$.ajax({
url: 'PartialView',
data: {},
type: 'Get',
success: function (response) {
$("#Questionpartial").html(response)
}
});
}
//code to update the questions according to the selected chapter
$("body").on("change", "#Qpartial", function () {
var CatgId = $("#Qpartial").val();
$.ajax({
url: 'PartialView1',
data: { id: CatgId },
type: 'Get',
success: function (response) {
$("#Questionpartial").html(response)
console.log(CatgId);
}
})
});
</script>
#model IEnumerable<EPQProjectTrackingTool.Models.QuestionCategory>
<table #*border="1" class="table table-striped"*#>
<thead>
<tr>
<th>
#Html.DisplayNameFor(model => model.Question)
</th>
</tr>
</thead>
<tbody>
#foreach (var item in Model)
{
<tr>
<td>
#*#Html.DisplayFor(modelItem => item.Question)*#
<input name="AreChecked" type="checkbox" checked="checked" value="#item.Question" /> #item.Question<br />
</td>
</tr>
}
</tbody>
</table>
there is one more file which is same HTML but only showing the full list as show in the above pic.
and the stored procedure in sql is:
CREATE procedure [dbo].[spGetAllMapping_Question_Category]
as
Begin
SELECT
mpq.UID,mpq.Question_ID_FK_1,eq.Question ,mpq. Cat_ID_FK_2, ec.Description, mpq.Valid_From,
mpq.Valid_To,c.Chapter_Name
FROM
EPQ2.Category ec,EPQ2.Questions eq, EPQ2.Mapping_Question_Category mpq, EPQ2.Chapter c
WHERE
mpq.Question_ID_FK_1 = eq.Question_ID_PK
and mpq.Cat_ID_FK_2 = ec.Cat_ID_PK
and c.Chapter_Id = eq.Chapter_Id
order by c.Ch_Sequence_ID , eq.Sequence_ID,ec.Cat_Name
End
CREATE procedure [dbo].[spGetQuestionsPerCategory](#category_Id int)
as
Begin
SELECT
eq.Question
FROM
EPQ2.Questions eq, EPQ2.Mapping_Question_Category mpq
WHERE
mpq.Question_ID_FK_1 = eq.Question_ID_PK
and mpq.Cat_ID_FK_2 = #category_Id;
End
the summary or similar example would be to select all the rows from a table and then put a filter which shows all the rows again but maybe make bold the filtered one and rest of them keep as it is.
Can't comment as I lack the reputation, so some liberties in assumption are gonna be taken and I can edit later if I made the wrong assumptions.
From my understanding you want a list of questions shown to the user, with all the questions matching the category from the dropdown to be selected.
If it's possible to change the return type from the stored procedure you could just have a sql function that returns question and whether it should be checked.
CREATE procedure [dbo].[spGetAllMapping_Question_Category](#category_Id int)
as
Begin
SELECT
mpq.UID,mpq.Question_ID_FK_1,eq.Question ,mpq.Cat_ID_FK_2, ec.Description, mpq.Valid_From,
mpq.Valid_To,c.Chapter_Name,
CASE
WHEN mpq.Cat_ID_FK_2 = #category_Id THEN 1
ELSE 0
END as 'Checked'
FROM
EPQ2.Category ec,EPQ2.Questions eq, EPQ2.Mapping_Question_Category mpq, EPQ2.Chapter c
WHERE
mpq.Question_ID_FK_1 = eq.Question_ID_PK
and mpq.Cat_ID_FK_2 = ec.Cat_ID_PK
and c.Chapter_Id = eq.Chapter_Id
order by c.Ch_Sequence_ID , eq.Sequence_ID,ec.Cat_Name
End
Bit value can be set to boolean in the questionCategoryDataAccess. I know some readers have a GetBoolean function or you can use some ternary operators.
Then you can set up an checkbox using this boolean.
#foreach (var item in Model)
{
<tr>
<td>
#if (item.Checked == true)
{
<input name="AreChecked" type="checkbox" checked="checked" value="#item.Question" /> #item.Question<br />
}
else
{
<input name="AreChecked" type="checkbox" value="#item.Question" /> #item.Question<br />
}
</td>
</tr>
}
Might be easier to use Html helpers but I followed the standard you had.
Hope this helps and if I made some wrong assumptions let me know and I'll do my best to help get the right solution.
I have a modal window for creating new object As you can see there three forms: 1) simple input to create "Name";
2) A dropdown with "Types" ;
3) A dropdown with "Ids";
I need to get data with types and Ids from DB, and as I can see in the browser and logs this part of process is going well, but when I fill all the forms and try to send them, there is always appears an Error, it happens because on server in variables "Types" and "IDs" written data from variable "Name", in short words it sent the data from input to all variables. This is a main question - why do it write data from input to all variables?? This is the html:
<tr>
<td class="collapsing">
<label>{{localization.common[locale].name}}</label>
</td>
<td>
<input type="text" placeholder="" ng-model="Name">
</td>
</tr>
<tr ng-controller="VirtualConnectorAddCtrl">
<td class="collapsing">
<label>{{localization.common[locale].VTypeID}}</label>
</td>
<td>
<select class="ui dropdown VTypeID" ng-model="VTypeID">
<option ng-repeat="item in virtualType" value= "'{{item.Id}}'">{{item.Name}}</option>
</select>
</td>
</tr>
<tr ng-controller="VirtualConnectorAddCtrl">
<td class="collapsing">
<label>{{localization.common[locale].account}}</label>
</td>
<td>
<select class="ui dropdown RunAsId" ng-model="RunAsId">
<option ng-repeat="list in runAccount" value= "'{{list.RunAsAccountId}}'">{{list.RunAsAccountName}}</option>
</select>
</td>
....
<div class="ui button blue" ng-click="createData(modal_id, Name, VTypeID, RunAsId)">{{localization.common[locale].add}}</div>
I had the same problem with creating "Account"(you can see on the image on left side menu: VirtualTypes, Account, VirtualConnectors), and there the issue was about $http params in controller
$scope.createData = function (obj, data, extra) {
....
if ($scope.dictFilter == 'accounts') {
$http({
method: 'GET',
url: appID + '/Insert_Methods.asmx/Insert_RunAsAccount',
params: { name: data, pasword: data}
}).then(function successCallback(response) {
Modals.close(obj)
getData();
}, function errorCallback(response) {
});
return;
} ....
When I replace 'password:data' to 'password:extra' the problem was solved, but with "VirtualConnectors" I couldn't find the way to do this (all creating processes are initializes by function "createData", and I am trying to add new block to that function)
if ($scope.dictFilter == 'virtualConnectors') {
$http({
method: 'GET',
url: appID + '/Insert_Methods.asmx/Insert_VirtualConnector',
params: {name: data, VtypeID: data, RunAsID:data }
}).then(function successCallback(response) {
Modals.close(obj)
getData();
}, function errorCallback(response) {
console.log("function createData doesn't callback");
});
return;
}
maybe it's about params, in this case there three of them (actually 4, including obj "modal"), but function acccept only 2 arguments (actually 3 -including "obj"), the function works for other cases, and in other cases params do not always fit to arguments... In internet not much information about "params", so I can't understand the logic of binding html and controller here. Obviously, in html-file function CreateData take "modal_id", "Name", "VtypeID" and "RunAsId" as arguments so in the controller this function should be set with arguments that can take such types of data (obj, string, string, string), but there is (obj, data, extra), I've tried to change function arguments in the controller: $scope.createData = function (obj, data, extra, string) {... and it doesn't help... I think I should write another function for this case, but what arguments should I put? And one more thing: is it right to use form with options created by ng-repeat for such case (when I need to send a string that is a property of an object)?
why do it write data from input to all variables?
Because, you are assigning data to all properties
params: {name: data, VtypeID: data, RunAsID:data }
you should do,
$scope.createData = function (modal_id, name, vTypeID, runAsId) {
and then:
if ($scope.dictFilter == 'virtualConnectors') {
$http({
method: 'GET',
url: appID + '/Insert_Methods.asmx/Insert_VirtualConnector',
params: {name: name, VtypeID: vTypeID, RunAsID: runAsId } // <-- Check this line
}).then(function successCallback(response) {
Modals.close(obj)
getData();
}, function errorCallback(response) {
console.log("function createData doesn't callback");
});
return;
}
similarly, correct the params for 'accounts'.
There are several bad practices in your code as well:
using ng-controller on each <tr> tag. Use it on table level
Passing modal_id when it's not being used.
passing name in your case data as password. It doesn't make any sense to name variable incorrectly. IF its a name, you shouldn't use password to refer it.
I will suggest you to get your code reviewed by some expert to avoid "bad coding practices" that you are following in your code.
I hope my answer will help you :)
I have a view with multiple sections. i would like to update sections individually using partial views and ajax.
I have this so far:
Controller:
[HttpPost]
public PartialViewResult userdetailssettings(UserDetails model)
{ .... }
View Html:
<div id="userDetailsPartial">
#Html.Partial("_user_details", Model.userdetails)
</div>
Partial Html:
<div class="form-group">
<div class="col-md-12">
#Html.TextBoxFor(x => x.Forename, new { #class = "form-control", placeholder = "Enter your forename" })
#Html.ValidationMessageFor(x => x.Forename)
</div>
</div>
<div class="form-group">
<div class="col-md-12">
#Html.TextBoxFor(x => x.Surname, new { #class = "form-control", placeholder = "Enter your surname" })
#Html.ValidationMessageFor(x => x.Surname)
</div>
</div>
Javascript on View:
var detailsUrl = "#Url.Action("userdetailssettings", "UserLogin")";
var detailsmodel = JSON.stringify(#Html.Raw(Json.Encode(#Model.userdetails)));
$(document).on('click touchstart', '#saveDetails', function () {
$.ajax({
type: "POST",
dataType: 'json',
data: detailsmodel,
url: detailsUrl,
contentType: "application/json"
}).done(function (res) {
$("#userDetailsPartial").html(res);
addresssearch();
});
});
The model is being passed to the controller by the ajax, however the values are not that of the inputs. They are the original values passed from the controller to open the view.
I have tried wrapping the partial in tags and also tried adding form tags inside the partial.
I have also tried putting this code:
var detailsUrl = "#Url.Action("userdetailssettings", "UserLogin")";
var detailsmodel = JSON.stringify(#Html.Raw(Json.Encode(#Model.userdetails)));
Inside the click function.
Nothing I do passes the updated values from the inputs.
I have thought of creating a new instance of the model from the inputs in the javascript i.e.
var detailsmodel = [ { Forename: $('#Forename').val(), Surname: $('#Surname').val() } ];
But if I am just creating json why can I not just convert the bound model to json.
why can I not just convert the bound model to json
This is because you are using MVC, not MVVM.
The "bound model" is one way from the controller to the view via the model; it's possible you're mixing the term "bound model" with "model" and "binding".
If you POST the form, you'll get the model in the Action (based on parameters of course), but if you pass via ajax, you'll need to get the current values from the form (as in your comment 'creating a new instance of the model from the inputs').
You can generate data to pass via AJAX in various ways, such as:
var data = $("form").serialize();
rather than adding every input manually.
var detailsmodel = JSON.stringify... is set when the view is generated and will not change automatically using MVC.
That's because the data you're passing is statically set at page load, based on #Html.Raw(Json.Encode(#Model.userdetails)).
You would need to use something like $form.serialize(), or otherwise create the post body from the actual fields on the page.
I don't know how to create dynamics javascript objects:
I've tried this code but it doesnt work...
Any Idea ?
Somebody tells me " Create the element outside the Ajax Scope " ...
I want to access one of my javascript objects, that are supposed to be sorted into an array called element.
For example, element[1] is one object, element[2] is another object.
The whole array of objects is built from a json ajax call with jquery.
It works very well for the reading ... but its not possible to modify my objects in another part of my program.
It's not asynchronous problem, it seems to be an object name problem like the [] .
Thanks a lot for your precious answers ! I'll try to modify the code... It's so exciting to create objects ! My goal is that the user is able to modify several differents forms at the same time, each form is an object but i don't wanna use Php hi hi... I generate the forms using my print function.
This is the snipe of my code :
/* PHASE 1*/
$.ajax({
type: "POST",
url: "lectureBdd.php",
dataType: "json",
success: function (data) {
//CREATE JAVASCRIPTS OBJECTS
var element = 0;
var element = [];
for (var i = 0; i < data.length; i++) {
element[i] = new Element([i], data[i].nom, data[i].
type, data[i].photo, data[i].taille, data[i].prix);
// OBJECTS TO SCREEN WORKS WELL INTO THE FUNCTION BUT NOT OUTSIDE
element[i].print();
alert(element[i].prix);
}
}
});
element[2].print(); /* Impossible to modify my object*/
/* CONSTRUCTOR CLASSE "ELEMENT" */
function Element(id,txtNom,txtType,txtPhoto,txtTaille,txtPrix){
this.id=id;
this.nom=txtNom;
this.type=txtType;
this.photo=txtPhoto;
this.taille=txtTaille;
this.prix=txtPrix;
this.print=affForm;
this.modif=modifForm;
}
/* THE REST OF THE CODE FOR INFORMATION IT CREATES AUTOMATICALLY A FORM WITH THE OBJECTS VARIABLES */
function affForm(){
var nom= this.nom;
var id=this.id;
var divid = 'div'+id;
var savebutton= 'savebutton'+id;
/* DYNAMIC FORM CREATION: */
/* http://stackoverflow.com/questions/17431760/create-a-form-dynamically-with-jquery- and-submit */
$("#share").append('<form action="sharer.php" method="POST">');
$("#share").append('<div id='+divid+' style="height:100px;background-color:white" > <img src="images/'+this.photo+'" height=100px width=150px />');
$("#share").append('<input type="text" placeholder="'+nom+'" name="routename" id="rname"/>');
$("#share").append('<input type="text" placeholder="'+this.taille+'" name="routename" id="rname"/>');
$("#share").append('<input type="text" placeholder="'+this.prix+' Euros" id="prix" name="prix" class="address"/>');
$("#share").append('<input type="text" placeholder="'+id+'" id="rdescription" name="routedescription" class="address"/>');
$("#share").append('<input type="text" placeholder="tags" id="tags" name="routetags"/>');
$("#share").append('<br><input type="submit" id="'+savebutton+'" value="Save" />');
$("#share").append('</div>');
$("#share").append(divid);
$( "#"+savebutton+"").click(function() {
modifForm(id);
alert( "Handler for .click() called. savebutton"+id+"" );
});
You're creating an Array of Elements inside of your Ajax function's success callback. That isn't exposed to the outer scope, so you can't index that array later on (it isn't defined). Declare it in the scope you're calling it from.
Also, Ajax is asynchronous: your array won't have any elements until its success function runs, which can take any amount of time. You'll need to operate asynchronously, too. Have a look at jQuery's implementation of promises, which should point you in the right direction.
var element = [];
$.ajax({
type: "POST",
url: "lectureBdd.php",
dataType: "json",
success: function (data) {
for (var i=0; i < data.length; i++){
element[i] = new Element([i],data[i].nom,data[i].type,data[i].photo,data[i].taille,data[i].prix);
// OBJECTS TO SCREEN WORKS WELL INTO THE FUNCTION BUT NOT OUTSIDE
element[i].print();
alert(element[i].prix);
}}})
.done(function(){
element[2].print(); // Ajax is async; you'll need to operate async, too. Using a promise here.
});
Using MVC4, how would I process the return value of a JsonResult action in an Ajax form?
All of the examples I was able to locate deal primarily with an html result (ActionResult).
I know this question is poorly framed, missing code and such, but I plan on providing my experience as the answer. Hopefully between this question and the answer there will be some good content.
In an ASP.net controller (C#) you can return a json result as follows (hope you already know it).
[httppost]
public ActionResult MyAction(){
//this is the most amazing content
return Json(new
{
MyResult = "ok",
MyData = "This is some string data!"
});
}
Its not clear for me what you expect from the answer or I am not sure whether this is what you need as an answer, but hope it will be helpful.
If you are using jquery ajax, you can access the controller and get the json results it returns.
$.ajax({
type: "POST",
URL: "/MyController/MyAction",
dataType: "text"
})
.success(function(data){
var dataobj = $.parseJSON(data);
var result = dataobj.MyResult;
var msg = dataobj.MyData;
});
When you are using return new Json(); the server response is of ContentType application/json. But, to use Jquery's parseJSON function correctly, you need to pass the json to the function as a string, otherwise it do not parse it correctly. So, to get the json result as a string or 'text' you need to add dataType: "text" as an option to $.ajax{}. Then the server returns its response as plain text and you can parse json using jquery's parseJSON function. It will return a dynamically created object which includes data returned as json. So you can access those data using the names included in the json string.
Hope this will be helpful somewhat.
So most examples/tutorials on the web will instruct you to return a view via your HttpPost action method. When doing this you would set the 'UpdateTargetId' and InsertionMode properties on the AjaxOptions object.
But if you want to return data and work with it via javascript, the above method falls short.
Rather, you will need to set the OnSuccess method of the AjaxOptions object.
As you can see from the documentation, OnSuccess contains zero helpful information. To use it correctly you need to provide the name of a javascript function available on the current page. This will be used callback-style so make sure you use the appropriate syntax for your use case.
Here's a little demonstration:
Controller methods:
<HttpGet>
Function AjaxIndex() As ActionResult
Dim model As AjaxFormModel = New AjaxFormModel
' AjaxFormModel is a custom class. Architect it as you see fit.
Return View(model)
End Function
<HttpPost>
Function AjaxIndex(ByVal model As AjaxFormModel) As JsonResult
Dim result As AjaxFormResult = Nothing
' AjaxFormResult is a custom class. Fill it in with properties that make sense for you. I personally include .MessageType and .Payload properties.
' TODO: be sure you spin up a new object to pass to the `JsonResult`.
Return New JsonResult With {.Data = result, .JsonRequestBehavior = JsonRequestBehavior.AllowGet}
End Function
Html
Using Ajax.BeginForm("AjaxIndex", "Bootstrap",
routeValues:=Nothing,
ajaxOptions:=New AjaxOptions With {.HttpMethod = "POST",
.OnSuccess = "updateAjaxForm"},
htmlAttributes:=Nothing)
#<text>
<div class="row">
<div class="col-sm-12" id="UnknownError_message">
</div>
</div>
<div class="row">
<div class="col-md-12">
<input type="text" name="Name" />
<div id="Name_message"></div>
</div>
</div>
<div class="row">
<div class="col-md-12">
<input type="submit" class="btn btn-default" value="Save" />
</div>
</div>
</text>
End Using
javascript / jQuery
<script type="text/javascript">
function updateAjaxForm(data) {
//data is a fully reconstituted javascript object at this point. Thank you MVC!
var messageElement = $('#UnknownError_message');
switch (data.MessageType) {
case 0: // Error message
messageElement.html('Error: ' + data.Message);
break;
case 1: // Textual message
messageElement.html('Info: ' + data.Message);
break;
default:
messageElement.html('Unforseen Error.');
}
}
</script>