Send complex JavaScript object to ASP.Net MVC Action - javascript

This seems to be quite a common theme and a few people have given some very constructive answers, but I'm still struggling to get my attempt to work.
The problem is much the same as this one for example, except that I'm only trying to send a single complex object instead of an array.
My controller looks like this:
[AcceptVerbs (HttpVerbs.Put)]
[Authorize]
[JsonFilter(Param="Designer", JsonDataType=typeof(Designer))]
public JsonResult SaveProfile(Designer Profile)
{
ProfileRepository Repo = new ProfileRepository();
Designer d = Repo.GetById(Profile.ID);
d.Comments = Profile.Comments;
d.DisplayName = Profile.DisplayName;
d.Email = Profile.Email;
d.FirstName = Profile.FirstName;
d.LastName = Profile.LastName;
Repo.Update(d);
return Json(Profile);
}
The code for retrieving the page data and posting it looks like this:
$('#save-profile').click(function () {
var Profile = {};
var context = $('#profile-data')[0];
$('span', context).each(function () {
Profile[this.id] = $(this).text();
});
Profile.ID = $('h3', context).attr('id');
console.log(Profile);
//var DTO = { 'Profile': Profile };
$.ajax({
type: "PUT",
url: "/Home/SaveProfile",
data: { 'Profile': Profile },
success: function (data) {
console.log(data);
}
});
});
The object is being correctly created and posted to the server (I've tried using POST and PUT, by the way), the server appears to be receiving an object instance, but the properties are - as usual - all null.
What am I missing? I've tried using the approach (adapted) from the example question linked above, but still don't seem to be getting any closer to the solution. Any help appreciated.

As it turns out, there's nothing wrong with the ActionResult method itself and neither is there any issue with the JavaScript object or Ajax post. The problem actually lies in the custom filter that decorates the ActionResult and the parameter being set for its param value.
The following attribute has a parameter of "Designer" set for the name of the parameter I'm trying to pass in. I've supplied this as both the parameter name and the type.
[JsonFilter(Param="Designer", JsonDataType=typeof(Designer))]
The correct version should be:
[JsonFilter(Param="Profile", JsonDataType=typeof(Designer))]

Related

Javascript Passing a Parameter to a Controller

I am trying to call the propDetails function and pass an ID to it. Then pass the same ID to the Static controller but I keep on getting an error: "id = id" (second ID doesn't exist).
I am sorry for this silly question and I can't figure out what I am doing wrong...
function propDetails(id) {
var $detailDiv = $('#detailsDiv'), url = $(this).data('url');
$.get( '#Url.Action("PropDetails", "Static", new { id = id })', function(data) {
$('#detailsDiv').html(data);
});
}
Any guidance would be greatly appreciate.
The id variable is not available in the Razor helper, what you can do is concatenate the id after the Url.Action helper has finished:
function propDetails(id) {
var $detailDiv = $('#detailsDiv'), url = $(this).data('url');
$.get('#Url.Action("PropDetails", "Static")' + id, function(data) {
$('#detailsDiv').html(data);
});
}
In the long run you would want to render a form to serialize your id as part of the request, written as $("form").serialize().
It is much easier to append more fields to an action that uses a complex type as a parameter. Your new code would look as follows:
$.get($detailDiv.find("form").attr("action"),$detailDiv.find("form").serialize(), function(data){
$('detailsDiv').html(data);
});
Your form object would be created in your HTTPGET request in MVC, returning the view with your built #Html.BeginForm() helper, which is part of innerHtml of detailsDiv, that can then be serialized using $("form").serialize()
I hope this is clear and fully answers how to fix the issue. I will modify if it is off base and adds more muddle to the mix of Javascript and MVC.

How do I append more data to an AngularJS model?

So far I'm having no issue setting up an AngularJS model in my Rails application and giving it data to access on the front-end. I even set it up to be populated with data from an AJAX request using $http. However, I need this this model to contain the data of multiple $http calls. Here's the code I've got thus far:
function DropboxCtrl($scope, $http) {
var $infiniteLoader = $(".infiniteLoader");
var theUIDS = $infiniteLoader.attr('data-dropbox-uids').split(',');
if($infiniteLoader.attr('data-dropbox-uids') != "") {
var theData = {};
$.each(theUIDS, function(key) {
$http({ url: '/dropbox/files/get', method: 'GET', params: { uid: theUIDS[key] }}).success(function(data) {
theData = data;
});
});
$scope.dropboxes = theData;
}
}
I have a method called DropboxCtrl which will start by getting all the UID's that I need to call a GET request on. I loop through each of them and then append data to theData which is a Javascript object. After the each I make my dropboxes model equal to the value of theData. Current I've got the method returning absolutely nothing and no Javascript errors. I am positive that my url works completely and actually did get the code working with just one AJAX request like such:
$.each(theUIDS, function(key) {
$http({ url: '/dropbox/files/get', method: 'GET', params: { uid: theUIDS[key] }}).success(function(data) {
$scope.dropboxes = data;
});
});
However... that code block only returns the last AJAX call because the other ones are overwritten. Maybe what I'm missing is just incorrect Javascript, however, maybe what I'm missing is just a lack of understanding the "Angular way" of things. I'm skilled in Javascript and jQuery, but very new to Angular. Any help?
AngularJs is a high level Javascript framework. The code ultimately is javascript. Within your $each, you can push results to an array or to an initialized collection like
$scope.dropboxes = [{uid:1234}, {uid:2345}] and so on.
within the $each, locate the record for uid and attach the results.
I usually use underscorejs library for operations on collections, arrays etc.
so something like
_.findWhere($scope.dropboxes, {uid: data.uid }).data = data;
assuming the data that is returned has uid in it. If not then there should be another way to map the results to the request. Note that there is no guarantee of the order of responses, so you cannot use array indexes to map results.

What is the best strategie to send complex data with ajax

I have some informations in a form to send to the server as a (complex) array (or Object if you prefer) with JS/jQuery. (jQuery 1.7.2)
I'm thinking about JSON to solve the problem smartly. My code works right now, but i want to know if its possible to do it better.
So this example is pretty typical (The data are more complex irl) :
dataSend = { 'id': '117462', 'univers': 'galerie', 'options' : { 'email': 'hello#world.com', 'commenataire': 'blabla', 'notation' : '4' } };
$.ajax({
url: "/ajax/ajaxMavilleBox.php",
data: JSON.stringify(dataSend),
success: function(x){
smth();
}
});
In an another context, i have to make the exact same thing without JSON.
With the same example :
dataSend = { 'id': '117462', 'univers': 'galerie', 'options' : { 'email': 'hello#world.com', 'commenataire': 'blabla', 'notation' : '4' } };
$.ajax({
url: "/ajax/ajaxBox.php",
data: $.param(dataSend),
success: function(x){
smth();
}
});
Obviously, I missing something.
The url is :
http://www.mywebsite.com/ajax/ajaxBox.php?id=117462&univers=galerie&options=%5Bobject+Object%5D
And the url should be :
http://www.mywebsite.com/ajax/ajaxBox.php?id=117462&univers=galerie&options[email]=hello#world.com&options[commenataire]=blabla&options[notation]=3
There is any easy way to do it (I hope I don't have to edit the data myself in a loop or something)
Edit : Solution for the second part
Ok, the last part without JSON is correct. In fact, i was using an older version of jQuery in my page.
$.param is not so good with jQuery < 1.4
More information here Param Doc
I would suggest setting the type: 'POST', otherwise you will have a data limit eqvivalent of the browsers query string length.
If you use the post method, you should send the data as a json-string. Something like:
data: { DTO: JSON.stringify(dataSend) }
You need to use json2.js if window.JSON is undefined (like in ie7 for example).
If you are using PHP on the serverside, you can fetch the object using:
$data = json_decode($_POST['DTO']); //will return an associative array
or ASP.NET
public class DataSctructure
{
public string id { get; set; }
public string univers { get;set; }
//etc...
}
var data = HttpContext.Current.Request.Form['DTO'];
DataSctructure ds = new JavaScriptSerializer().Deserialize<DataSctructure>(data);
//properties are mapped to the ds instance, do stuff with it here
as mentioned by #Johan POST shouldbe used here instead of GET
you can view data you are sending by using the Developer options in the browser you are using just press f12
also make sure you are using jquery >= 1.4
the incorrect serialized string in the url is the way that $.param() used to serialize prior to 1.4 version

backbone model fetch JSON element by ID

I am using backbone for the first time and I am really struggling to get it to function correctly with a JSON data file.
I have a model Like so:
window.Test = Backbone.Model.extend({
defaults: {
id: null,
name: null,
},
url: function() {
return 'json/test.json/this.id';
},
initialize: function(){
}
});
When a test item is clicked I then try to bring up the details of the pacific model that was clicked by doing
testDetails: function (id) {
var test = new Test();
test.id = id;
test.fetch({ success: function(data) { alert(JSON.stringify(data))}});
},
However this does not work, I am unable to correctly say "get the JSON element with the passed ID"
Can anyone please show me how to correctly structure the models URL to pull the element with the ID.
Thanks
The problem here is that you're treating your JSON data file like a call to a server. That won't work and it's the reason you're getting a 404. If you're accessing a file locally, you have to load the file first. You can do this with jQuery using the .getJSON() method, or if the file's static, just load it into memory with a script block (though you'll probably need to assign a var in the file). Most likely, you'll use jQuery. An example of this can be found here:
Using Jquery to get JSON objects from local file.
If this is an array of JSON, you can load the array into a collection, and use the "at" method to access the particular element by id. If it's entirely JSON, you'll have to create a custom parser.
your url is incorrect for one. you are returning the literal string 'this.id'. you probably want to do something more along the lines of
url: function () {
return 'json/test.json/' + this.id;
}
I would start by fixing your url function:
url: function() {
return 'json/test.json/' + this.get('id');
}
The way you have it now, every fetch request, regardless of the model's id, is going to /json/test.json/test.id

Knockout.js ko.mapping.toJS not refreshing data in my view

I fetch a json object from the server and populate my view. I then change the data, push it back to the server. I then fetch a new copy of the data hoping it will refresh my view with any changes. However that doesn't happen. TIA
$(document).ready(function() {
var customer_id = get_customer_id();
var data = load_model();
contract_model = ko.mapping.fromJS(data,{});
ko.applyBindings(contract_model);
}
function load_model(){
var url = '/ar/contract_json?contract_id='+get_contract_id();
var data = '';
$.ajax({
type:'GET',
url:url,
async:false,
success: function(returningValue){
data = returningValue;
}
});
return data;
}
This initial load works fine. I then do some stuff and change one of the observables and push that data back to server. Server gets the update and then I do a new fetch of the data so that view will refresh (i know i can pass back the new data in one step but this in code i haven't refactored yet).
function refresh_data(contract_model){
var url = '/ar/contract_json?contract_id='+get_contract_id();
$.post(url,function(data){
console.log(data);
ko.mapping.fromJS(contract_model,{},data);
ko.applyBindings(contract_model);
console.log(ko.mapping.toJS(contract_model))
});
}
function refresh_data(contract_model){
var url = '/ar/contract_json?contract_id='+get_contract_id();
$.post(url,function(data){
console.log(data);
ko.mapping.fromJS(contract_model,{},data);
console.log(ko.mapping.toJS(contract_model))
});
}
function push_model(contract_model,refresh){
var url = '/ar/update_contract';
var data = {'contract':ko.mapping.toJSON(contract_model)}
delete data['lines'];
$.post(url,data,function(return_value){
if (refresh){
refresh_data(contract_model);
};
});
}
The console messages all show the new data coming back but my view never updates.
I believe the problem is with the order of parameters you pass into the ko.mapping.fromJS function when you are updating contract_model.
You have:
ko.mapping.fromJS(contract_model,{},data);
you want:
ko.mapping.fromJS(data, {}, contract_model);
#seth.miller's answer is correct. You can also leave out the middle "options" parameter if your contract_model is the same one that was mapped earlier. If there are only two arguments, ko.mapping.fromJS checks if the second argument has a "__ko_mapping__" property. If so, it treats it as a target, otherwise it treats it as an options object.
Based upon #DBueno's observation - for anyone using typescript I strongly recommend commenting out this method signature from your knockout.mapping.d.ts file.
// fromJS(jsObject: any, targetOrOptions: any): any;
Yes - just comment it out.
You'll then get a compile time error if you try to do :
ko.mapping.fromJS(item.data, item.target);
and you can replace it with the much safer
ko.mapping.fromJS(item.data, {}, item.target);
Safer because whether or not item.target has been previously mapped (and therfore would have a __ko_mapping__ property) it will always copy the properties.

Categories

Resources