I have this Index action:
public ActionResult Index()
{
var repo = (YammerClient) TempData["Repo"];
var msgCol = repo.GetMessages();
ViewBag.User = repo.GetUserInfo();
return View(msgCol.messages);
}
GetMessages returns a list of POCO messages and GetUserInfo returns a POCO with the info of the user (id, name, etc).
I want to fill a javascript variable with the JSON representation of the user info.
So I would want to do something like this in the view:
...
<script>
var userInfo = "#ViewBag.User.ToJson()"
</script>
...
I know that doesn't work, but is there a way to do that? I want to avoid having to do an ajax request once the page is loaded just to get the user info.
In View you can do something like this
#{
var jss = new System.Web.Script.Serialization.JavaScriptSerializer();
var userInfoJson = jss.Serialize(ViewBag.User);
}
in javascript you can use it as
<script>
//use Json.parse to convert string to Json
var userInfo = JSON.parse('#Html.Raw(userInfoJson)');
</script>
Was using this solution for simple objects. But I had some problems getting an array to js objects so I'll just leave what I did here.
C#
#{
using Newtonsoft.Json;
ViewBag.AvailableToday = JsonConvert.SerializeObject(list);
}
js
var availableToday = JSON.parse('#Html.Raw(ViewBag.AvailableToday)');
Client-Side Code:
This is an ajax call to a .Net MVC Controller:
var clientStuff;
$.ajax({
type: 'GET',
url: '#Url.Action("GetStuff", "ControllerName")',
data: {},
dataType: "json",
cache: false,
async: false,
success: function (data) {
clientStuff = data;
},
error: function(errorMsg) {
alert(errorMsg);
}
});
Server-Side Code:
CONTROLLER:
public JsonResult GetStuff()
{
return Json(_manager.GetStuff(), JsonRequestBehavior.AllowGet);
}
MANAGER:
public IEnumerable<StuffViewModel> GetStuff()
{
return _unitofWork.GetStuff();
}
UNIT OF WORK:
public IEnumerable<StuffViewModel> GetStuff()
{
var ds = context.Database.SqlQuery<StuffViewModel>("[dbo].[GetStuff]");
return ds;
}
Unit of Work can be a query to a sproc (as I have done), a repository context, linq, etc.
I'm just calling a sproc here for simplicity, although it could be argued that the simplicity lies with Entity Framework and Linq.
You can change this line :
ViewBag.User = repo.GetUserInfo();
To
ViewBag.User = new HtmlString(repo.GetUserInfo());
You should add using Microsoft.AspNetCore.Html; or using System.Web; if HtmlString is not accessible.
Related
I am currently trying this, but I keep seeing the dreaded error:
Unexpected token o in JSON at position 1
I am struggling to find a solution and was wondering if anyone has any tips on how to solve this?
The class being serialized to JSON:
[Serializable]
public class GeoCoordinate
{
public GeoCoordinate()
{
}
[JsonProperty(PropertyName = "lat")]
public double Latitude { get; }
[JsonProperty(PropertyName = "long")]
public double Longitude { get; }
public GeoCoordinate(double latitude, double longitude)
{
Latitude = latitude;
Longitude = longitude;
}
public override string ToString()
{
return string.Format("{0},{1}", Latitude, Longitude);
}
}
Ajax call:
function getLocationData() {
jQuery.ajax({
url: abp.appPath + "Home/GetLocationsAsync",
type: "GET",
dataType: "json",
async: true,
success: function (data) {
var myArray = jQuery.parseJSON(data);
locations = [];
$.each(myArray, function (index, element) {
locations.push([element.lat, element.long]);
});
}
});
}
Controller:
[HttpGet]
public async Task<JsonResult> GetLocationsAsync()
{
var cords = await _practiceAppService.GetAllGeoCoordinates();
return Json(cords);
}
AppService:
public async Task<IList<GeoCoordinate>> GetAllGeoCoordinates()
{
var geoCoordinates = await Repository.GetAll()
.Where(x => !x.Disabled && !x.Latitude.Equals(0) && !x.Longitude.Equals(0))
.Select(x => new GeoCoordinate(x.Latitude, x.Longitude))
.ToListAsync();
return geoCoordinates;
}
Console.log of data before attempted call to parseJSON:
console.log(data);
var myArray = jQuery.parseJSON(data);
Coincidentally, there is a section called The ASP.NET Boilerplate Way that exactly addresses this.
Note that only point 2 is specific to ABP:
GetLocationsAsync returns a JSON object and not a string, so you should not call parseJSON.
You can reproduce the error message with: jQuery.parseJSON({});
ABP wraps JsonResult. From the documentation on AJAX Return Messages:
This return format is recognized and handled by the abp.ajax function.
You could use [DontWrapResult] attribute, but you might as well leverage on ABP here. abp.ajax handles the display of error messages if you throw a UserFriendlyException.
Since ajax is asynchronous, getLocationData cannot return locations directly.
You can return a chained Promise. If you're new to Promises, read Using Promises first.
There's a neater way than $.each and push.
You can use map.
Finally:
function getLocationData() {
return abp.ajax({
url: abp.appPath + "Home/GetLocationsAsync",
type: 'GET'
}).then(function (result) {
return result.map(function (element) {
return [element.lat, element.long];
});
});
}
Usage:
getLocationData().then(function (locations) {
console.log(locations);
});
ASP.NET Boilerplate wraps ASP.NET MVC action results by default if the return type is a JsonResult. So if you want to get the result you can disable wrapping. Try adding [DontWrapResult] attribute to the GetLocationsAsync method.
[DontWrapResult]
[HttpGet]
public async Task<JsonResult> GetLocationsAsync()
{
var cords = await _practiceAppService.GetAllGeoCoordinates();
return Json(cords);
}
PS: You don't need to add this attribute. You can get it from result field. Inspect the response via your browser's dev console to see how it's wrapped.
I'm trying to do a simple action with some JavaScript code. I've got some items on a scheduler (DevExpress scheduler component). When I'm double clicking on an appointment (an item then), it should raise an JS function which is the case. My function should get the selected appointment id and pass it to Controller Action. Here is my JS code :
function DoubleClick() {
debugger;
var apt = GetSelectedAppointment(scheduler);
var aptid = apt.appointmentId;
$.ajax({
type: "POST",
url: "/Home/GetAppId",
data: { id: aptid },
dataType: 'json',
success: function () {
alert("ok");
},
error: function () {
alert("error");
}
});
}
And here is my C# code :
[HttpPost]
public JsonResult GetAppId(int id)
{
context = new SchedulingDataClassesDataContext();
DBAppointment app = (from a in context.DBAppointment where a.UniqueID == id select a).FirstOrDefault();
return Json(new {rep = app});
}
As you can see in my JS code, I'm not doing anything special in case of success. However, I never reach the success part. Plus, when I'm looking at the Chrome dev tool (F12), I'm getting that red error message.
POST http://localhost:25206/Home/GetAppId 500 (Internal Server Error)
Anything that I'm doing wrong?
Man, you need to force things as follows
return Json(new {rep = app},"text/json",JsonRequestBehavior.AllowGet);
In addition, mind your navigation properties (if any) in order to avoid circular reference
According to your error your problem somewhere in select your data from DB or creating anonymous object when you try to serialize it to Json. I rewrite your select to simplify it and not creating any anonymous objects when return it from Controller like this:
[HttpPost]
public JsonResult GetAppId(int id)
{
context = new SchedulingDataClassesDataContext();
DBAppointment app = context.DBAppointment.FirstOrDefault(x => x.UniqueID == id);
return Json(app);
}
Does it work like this?
Please remove the name of the property in ajax data and edit that property as below.
function DoubleClick() {
debugger;
var apt = GetSelectedAppointment(scheduler);
var aptid = apt.appointmentId;
$.ajax({
type: "POST",
url: "/Home/GetAppId",
data: aptid,
dataType: 'json',
success: function () {
alert("ok");
},
error: function () {
alert("error");
}
});
}
and edit your controller as follows
[HttpPost]
public JsonResult GetAppId([FromBody]int id)
{
//...
}
Please read this blog post which is a good read and allowed me to understand what's going on.
http://encosia.com/using-jquery-to-post-frombody-parameters-to-web-api/
The original question that I asked
Simple post to Web Api
Try changing the last line of the method to:
return Json(new { rep = app }, JsonRequestBehavior.AllowGet);
You need to tell C# to allow the json to be returned to the client.
So basically Here is what I do:
in body - onload method I call this javascript function
function TestN() {
var list = new Array();
var allElements = document.getElementsByTagName('*');
$("*[wordNum]").each(function ()
{
var endRes = {
ControllerName: this.id,
WordNumber: this.getAttribute("wordNum")
};
list.push(endRes);
});
jQuery.ajax({
url:' #Url.Action("Translate")' ,
contentType: "application/json",
dataType: "json",
data: { List : JSON.stringify(list) }
,
traditional: true
})
}
what it does - it searches all the controlls with attribute "WrdNum" and then I make an ajax request to the MVC Translate action!
In the Translate Action I make a request to a web service which populates a list of type - TranslateModel
public ActionResult Translate(string List)
{
List<TranslateModel>listto = WebServiceBea.TranslateList(1, List);
return View(listto);
}
Also Here is my TranslateModel
public class TranslateModel
{
public string ControllerName { get; set; }
public string WordNumber { get; set; }
public string Description { get; set; }
}
So basically my question is -> what type should I return to a view - > and how to return this list to a javascript or jquery function which has to set the innerHtml property of some html controls with the record from this list.**
I now that it's strange but that's my task
EDIT
Thanks so much for the help. But now I've got another problem:
After I changed my javascript and put. Done method so I could get the data from the server it looks something like this :
$(document).ready(function () {
var list = new Array();
$("*[wordNum]").each(function () {
var endRes = {
ControllerName: this.id,
WordNumber: this.getAttribute("wordNum")
};
list.push(endRes);
});
jQuery.ajax({
url: ' #Url.Action("Translate")',
contentType: "application/json",
dataType: "json",
data: { List: JSON.stringify(list) }
,
traditional: true,
}).done(function (result)
{
alert ("HII") ;
});
});
no matter what I put in the .done function it never executes. It seems like the controller doesn't know where to return the result. |I| don't now. Can something happen from the fact that I'm making this request from the .layout page - on document ready. s
this looks like a greet place to use knockout js.
here is a great step by step for using knockout with the mvc view
so the method will only return json, the view will not have a model just a call to get the json
if you are going to use $.post to pull your data you could return your list as json
[AcceptVerbs(HttpVerbs.Get|HttpVerbs.Post)]
public ActionResult Translate(string List)
{
List<TranslateModel>listto = WebServiceBea.TranslateList(1, modelObj);
return Json(listto);
}
Looking at what you are posting to the action method, it should already be a list of that type. MVC should do the heavy lifting and transform it to the objects you have.
if however you would like to handle the return yourself you can do something like
jQuery.ajax({
url:' #Url.Action("Translate")' ,
contentType: "application/json",
dataType: "json",
data: { List : JSON.stringify(list) },
traditional: true
}).success(function( returnData, returnStatus)
{
//some code to handle the list of objects reutrned
});
You've already got an answer, but consider the following for cases where you may have controller actions called by javascript:
public ActionResult GetItems(string id)
{
var MyList = db.GetItems(id);//returns a list of items
if (Request.IsAjaxRequest())//called from javascript via AJAX
{
return Json(MyList, JsonRequestBehavior.AllowGet);
}
else //regular hyperlink click
{
return View(MyList);
}
}
To use the list, do the following
$.ajax({url: "'#Url.Content("~/controllername/GetItems")?id=' + id"})
.done(function(result){
var mylist = result.responseText.evalJSON();//this is your list of items
for(i=0;i<mylist .length;i++)
{
var myitem = mylist[i];
}
});
NEVERRRR NEVERRR Forge to put jsonRequestBehavior.AllowGet
Thanks alot for everyone for the help
I have a controller action that takes two objects as arguments. I can't get it to work at all they always come back as null. My latest try looks like below. I have tried many other variations. In this case the FormInfo class is a class with 2 properties that are types for Form1 and Form2. I have also tried having the controller take in the two classes as arguments and the data part looked like { form1: form1Data, form2: form2Data } that was not working as well. I also tried using JSON.stringify to form the data with no luck.
Looking in the network monitor I see the data going back to the server it's just the engine that MVC uses to decode the query string to the objects can't handle what I'm passing back.
Thanks in advance for any information!
ClientSide
var formData = $("#form1").serialize();
var formData2 = $("#form2").serialize();
var formInfo = new Object();
formInfo.FormData = formData;
formInfo.FormData2 = formData2;
$.ajax({
url: 'Controller/Action',
type: 'POST',
data: formInfo,
success: function (data) {
//do stuff
}
});
ServerSide
public ActionResult SaveForms(FormInfo formInfo)
{
//Do Stuff here
}
You could use the a JSON request in conjunction with the .serializeArray() jQuery method. Let's suppose that you have the following model:
public class FormInfo
{
public Form1Data Form1Data { get; set; }
public Form2Data Form2Data { get; set; }
}
where Form1Data and Form2Data are some completely arbitrary complex classes. Now on the client we suppose that you have 2 distinct forms (#form1 and #form2 whose input element names match your complex structures in terms of default model binder wire format). Sending an AJAX request and packing the 2 forms together becomes trivial:
var form1Data = {};
$.each($('#form1').serializeArray(), function () {
form1Data[this.name] = this.value;
});
var form2Data = {};
$.each($('#form2').serializeArray(), function () {
form2Data[this.name] = this.value;
});
$.ajax({
url: '#Url.Action("someaction", "somecontroller")',
type: 'post',
contentType: 'application/json; charset=utf-8',
data: JSON.stringify({
form1Data: form1Data,
form2Data: form2Data
}),
success: function (result) {
// TODO: do something with the result
}
});
And of course the controller action you are POSTing to looks like this:
[HttpPost]
public ActionResult SomeAction(FormInfo formInfo)
{
...
}
I am doing something like this but i have a object and other Formdata to pass my Controller
var discrepancy = self.newCptyReply();
if ($('#UploadFile')[0]) {
var upload = new FormData(),
file = $('#UploadFile')[0].files[0];
upload.append('id', self.globalMessageId());
upload.append('discrepancy', ko.toJSON(discrepancy));
upload.append('doc', file);
}
datacontext.saveCptyToReply(self, upload);
And in controller signature
public ActionResult SaveCptyToReply(Guid id, Trade discrepancy, HttpPostedFileBase doc)
But when it reaches Controller id , doc are ok but discrepancy is null... It has data when funciton is called..
What to do...
Good morning All,
I have a javascript variable in my view. I keep doing this...
var skinData = null;
and then on document.ready....
$.ajax({
type: 'POST',
url: 'theme/getskins',
data: {},
contentType: 'application/json; charset=utf-8',
success: function(data){
skinData = data;
}
});
my question is why am I doing this on after the view has loaded. I'm trying to do this in _ViewStart.cshtml
viewPage.ViewBag.SkinInfo = new JsonResult { Data = SkinManager.GetSkins() };
How can I take this value and output its value to my javascript variable. I don't think I need to do another request when I really want to push this to the client on the first trip. Any tips or advice is of course appreciated. How can I do this correctly? I tried a few variations of this but it obvious isn't working. Stuff like...
var skinData = #ViewBag.SkinInfo.Data;
This just outputs the namespace. Any ideas how to do this correctly?
Cheers,
~ck in San Diego
You will want to use some a serializer to convert your .GetSkins() method result into a json object. Either the built in JavaScriptSerializer or json.net
JavaScriptSerializer serializer = new JavaScriptSerializer();
viewPage.ViewBag.SkinInfo = serializer.Serialize(SkinManager.GetSkins());
And then in your view
var skinData = #Html.Raw(ViewBag.SkinInfo);
Here's a way of doing it using a Html helper. It will convert your object into json and put it into a javascript variable.
HtmlHelper extension method
public static MvcHtmlString Jsonize(this HtmlHelper helper, string variableName, object obj)
{
StringBuilder str = new StringBuilder();
str.Append("<script type='text/javascript'>");
str.Append("var ");
str.Append(variableName);
str.Append("=");
if (obj == null)
str.Append("null");
else
str.Append(JsonHelper.Serialize(obj));
str.Append(";");
str.Append("</script>");
return MvcHtmlString.Create(str.ToString());
}
The json serializer. I'm using the DataContractJsonSerializer in this case.
public class JsonHelper
{
public static string Serialize(object obj)
{
string json = null;
DataContractJsonSerializer serializer = new DataContractJsonSerializer(obj.GetType());
using (MemoryStream ms = new MemoryStream())
{
serializer.WriteObject(ms, obj);
json = Encoding.Default.GetString(ms.ToArray());
}
return json;
}
}
Once you have that done, you can just use it in your views to create a javascript variable that contains your object
#Html.Jsonize("data", ViewBag.SkinInfo.Data);
which will create something like this:
<script type='text/javascript'>
var data = { your serialized object };
</script>