I am using angularjs in asp.net
I made a controller with CRUD and am trying to get data from angularjs controller using $http service
Route params is getting correct querys from url, i tested that, but i get undefined error when requesting data
What am i doing wrong? :(
SongsController.cs method:
public ActionResult Index(string id)
{
/*var result = db.Songs.ToList();
return Json(result, JsonRequestBehavior.AllowGet);*/
string searchString = id;
var songs = from m in db.Songs
select m;
if (!String.IsNullOrEmpty(searchString))
{
songs = songs.Where(s => s.Title.Contains(searchString));
}
return Json(songs, JsonRequestBehavior.AllowGet);
}
songsService.js:
myApp.factory('songsService', ['$http', function ($http) {
var songsService = {};
songsService.getSongs = function (param) {
return $http.get('/Songs/Index/' + param);
}
return songsService;}])
songsController.js:
myApp.controller('songsController', ['$scope', '$routeParams', 'songsService', function ($scope, $routeParams, songsService) {
var search = $routeParams.query;
if (search == 'undefined' || search == null)
search = '';
getSongs(search);
function getSongs(searchText) {
songsService.getSongs(searchText)
.success(function (data) {
$scope.songs = data;
})
.error(function (error) {
$scope.status = 'Unable to load data: ' + error.message;
console.log($scope.status);
});
}}]);
EDIT:
Song class:
using System;
using System.Collections.Generic;
public class Song
{
public int ID { get; set; }
public string Title { get; set; }
public string Artist { get; set; }
public virtual ICollection<Navigation> Navigations { get; set; }
}
EDIT2: Navigation class:
using System;
public class Navigation
{
public int ID { get; set; }
public int SongID { get; set; }
public int PlaylistID { get; set; }
public virtual Song Song { get; set; }
public virtual Playlist Playlist { get; set; }
}
EDIT3:
If I name my .cs controller SongsController and navigate to url songs/index/something i get popup if i want to open or save something.json and just get redirected back to my default url defined by ngroute (#/songs/)
But, if i name .cs controller something else, like RandomController, if i navigate to same url i get this error:
A circular reference was detected while serializing an object of type 'System.Data.Entity.DynamicProxies.Navigation_7A1A3B789B740F23BAB0A6DAABE519BE3AF91C300893047C23FF2FD8C44E6705'.
EDIT4: I've come to point at which everything if my SongsController.cs looks like this:
public ActionResult Index(string id)
{
var song = new List<Song>
{
new Song{Title="Paint It Black",Artist="Rolling Stones"},
new Song{Title="People Are Strange",Artist="The Doors"},
new Song{Title="With Or Without You",Artist="U2"},
new Song{Title="Wish You Were Here",Artist="Pink Floyd"},
new Song{Title="Fluorescent Adolescent",Artist="Arctic Monkeys"},
new Song{Title="La Guitarra",Artist="Orjan Nilsen"},
new Song{Title="Ping Pong",Artist="Armin Van Buuren"},
new Song{Title="Fade Out Lines",Artist="The Avenger"},
new Song{Title="Redemption Song",Artist="Bob Marley"},
new Song{Title="Wherever I May Roam",Artist="Metallica"},
};
return Json(songs, JsonRequestBehavior.AllowGet);*/
}
If it' like that everything works, but if it looks like i've wrote in original post i get undefined error when i run $http.get :/
EDIT5: Okay, I believe the problem is i'm trying to send objects containing array of Navigation class objects, how can i solve this? :(
You have a circular reference on your Song class.
When the Json serializer tries to process it, it finds the Navigations property and tries to serialize that as well, the problem is that each Navigation object on that collection have a instance of the same Song, so it enters a infinite loop trying to serialize all of it over and over again.
That happens because EntityFramework has its lazyloading and automatically populate the classes as the serializer tries to access them.
To fix it, you can do two things, simply disable the lazyloading for that call in particular:
public ActionResult Index(string id)
{
db.Configuration.LazyLoadingEnabled = false;
string searchString = id;
var songs = from m in db.Songs
select m;
if (!String.IsNullOrEmpty(searchString))
{
songs = songs.Where(s => s.Title.Contains(searchString));
}
return Json(songs, JsonRequestBehavior.AllowGet);
}
The other option is to create a model with only the data you need to return and populate it manually (or using a mapper tool).
public ActionResult Index(string id)
{
db.Configuration.LazyLoadingEnabled = false;
string searchString = id;
var songs = from m in db.Songs
select m;
if (!String.IsNullOrEmpty(searchString))
{
songs = songs.Where(s => s.Title.Contains(searchString));
}
var mappedSongs = songs.Select(it => new { Title = it.Title, Artist = it.Artist }).ToList();
return Json(mappedSongs , JsonRequestBehavior.AllowGet);
}
Related
Question
I have a handful of ViewComponents that look like so:
public IViewComponentResult Invoke(BuyerViewModel buyer)
I'd like them to be able to accept either a BuyerViewModel, or a JSON string representing a BuyerViewModel. For example, when you pass JSON to a controller method from JavaScript, if that method expects an argument of type Dog, the controller automatically attempts to deserialize the JSON to an instance of Dog. I'm trying to mimic that behavior.
The goal would be that both of these examples work:
var buyer = new BuyerSummaryViewModel() { FirstName = "John" };
ViewComponent("Buyer", buyer);
ViewComponent("Buyer", "{\"Name\":\"John Smith\"}");
Why?
I'm trying to make a generic JavaScript method that can fetch a ViewComponent on the fly:
const fetchViewComponent = async (viewComponentName, viewModel) => {
let data = { viewComponentName, viewModel };
let html = await $.get(`/Order/FetchViewComponent`, data);
return html;
}
//Get a BuyerViewComponent (example)
(async () => {
let component = await fetchViewComponent("Buyer", `#Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject(Model.Buyer))`);
console.log(component);
})();
What I've Tried
If I specify that the ViewModel is a BuyerViewModel, it works. The JSON string is automatically deserialized into a BuyerViewModel.
public class FetchViewComponentRequest
{
public string ViewComponentName { get; set; }
public BuyerViewModel ViewModel { get; set; }
// ^^^^^^^^^^^^^^
}
[HttpGet]
public IActionResult FetchViewComponent(FetchViewComponentRequest request)
{
return ViewComponent(request.ViewComponentName, request.ViewModel);
}
The Issue
However, I don't want to specify the type; I want this to be generic. So I tried this:
public class FetchViewComponentRequest
{
public string ViewComponentName { get; set; }
public string ViewModel { get; set; }
// ^^^^^^
}
[HttpGet]
public IActionResult FetchViewComponent(FetchViewComponentRequest request)
{
return ViewComponent(request.ViewComponentName, request.ViewModel);
}
But as expected, request.ViewModel isn't the correct type; it ends up null in the Invoke method. I was hoping there was a flag or something more global I could specify so that it tries to implicitly deserialize this string into the expected type.
Is there an easier way to do this that I haven't considered? Or, if not, is the way I'm envisioning even possible?
(I'm using .NET Core 2.2)
Maybe make your FetchViewComponentRequest generic?
public class FetchViewComponentRequest<T>
{
public string ViewComponentName { get; set; }
public T ViewModel { get; set; }
// ^^^^^^^^^^^^^^
}
[HttpGet]
public IActionResult FetchViewComponent(FetchViewComponentRequest<BuyerViewModel> request)
{
return ViewComponent(request.ViewComponentName, request.ViewModel);
}
The method needs to have some knowledge of what type to make the object coming in.
public T Convert<T>(dynamic obj) where T:class,new()
{
T myob = null;
if (obj !=null && obj is T)
{
myob = obj as T;
}
else if (obj is string)
{
//convert to type
myob = JsonConvert.DeserializeObject<T>(obj);
}
return myob;
}
Ok, im not sure about what you need.
But here is a dynamic way to do it, without specifying <T>.
//Assume that the namespace is DynamicTypeDemo
public class DynamicType {
// eg "DynamicTypeDemo.Cat, DynamicTypeDemo"
public string TypeName { get; set; } // the full path to the type
public string JsonString { get; set; }
}
Now you could simple DeserializeObject
public object ToObject(DynamicType dynamicType){
var type = Type.GetType(dynamicType.TypeName);
// Here you could check if the json is list, its really upp to you
// but as an example, i will still add it
if (dynamicType.JsonString.StartsWith("[")) // its a list
type =(List<>).MakeGenericType(type);
return JsonConvert.DeserializeObject(dynamicType.JsonString, type);
}
And here is how it work
var item = new DynamicType(){
TypeName = "DynamicTypeDemo.Cat, DynamicTypeDemo", // or typeof(Cat).AssemblyQualifiedName
JsonString = "{CatName:'Test'}"; // And for a list "[{CatName:'Test'}]"
}
object dynamicObject= ToObject(item); // return it to the javascript
Cat cat = dynamicObject as Cat; // Cast it if you want
I am building a scheduling system using fullcalendar for MVC, my get event retrieves from a view for a specific location.
However, my post / save event inserts into the table that the view is made from, containing all locations.
I am getting an error when I try to add the new event to the data connection.
"The field Location must be a string or array type with a maximum length of '1'." string
PropertyName "Location" string
I tried to set the string for the event manually before adding it to the data connection but this isn't working for some reason. Could it be me not declaring the string correctly?
//Actions for Calendar 5
public JsonResult GetEvents5()
{
using (CalgaryNEEntities dc = new CalgaryNEEntities())
{
var events = dc.CalgaryNEEvents.ToList();
return new JsonResult { Data = events, JsonRequestBehavior = JsonRequestBehavior.AllowGet };
}
}
[HttpPost]
public JsonResult SaveEvent5(EventsAllLocation e)
{
var status = false;
using (InsertEntities dc = new InsertEntities())
{
if (e.EventID > 0)
{
//Update the event
var v = dc.EventsAllLocations.Where(a => a.EventID == e.EventID).FirstOrDefault();
if (v != null)
{
var locationstring = "Calgary NE Kitchens";
v.CompanyName = e.CompanyName;
v.Start = e.Start;
v.End = e.End;
v.KitchenNumber = e.KitchenNumber;
v.Location = locationstring;
}
}
else
{
var locationstring = "Calgary NE Kitchens";
e.Location = locationstring;
dc.EventsAllLocations.Add(e);
}
dc.SaveChanges();
status = true;
}
return new JsonResult { Data = new { status = status } };
}
Here is the EventsAllLocation definition:
public partial class EventsAllLocation
{
public int EventID { get; set; }
public string Location { get; set; }
public string CompanyName { get; set; }
public System.DateTime Start { get; set; }
public Nullable<System.DateTime> End { get; set; }
public string KitchenNumber { get; set; }
}
Any tips or help would be greatly appreciated, thanks!
The answer is staring you in the face !! LOL
"The field Location must be a string or array type with a maximum
length of '1'." string PropertyName "Location" string
Background
I have an incomplete project built on MVC 5, EF 6 DB First & DevExpress extensions with following code spec (all original non-English variable names changed & entire code simplified to comply MCVE):
Model (Namespace: ProjectName.Models)
public class DBContext : DbContext
{
public DBContext : base("ConnectionStringName")
{
public DbSet<WinnerTable> Winners { get; set; }
public DbSet<UnitTable> Units { get; set; }
public DbSet<CustomerTable> Customers { get; set; }
}
}
[Table("WinnerTable")]
public class WinnerModel : IWinnerRepository
{
public String WinnerID { get; set; }
public String CustomerID { get; set; }
public String CustomerName { get; set; }
public String TranDate { get; set; }
public List<UnitModel> UnitList { get; set; }
public List<UnitModel> GetUnitList(String sessionID, DateTime tranDate)
{
// query to unit list
using (var DB = new DBContext())
{
var query = (from unit in DB.Units
where unit.SessionID == sessionID && unit.TranDate = tranDate
select new UnitModel()
{
// unit table to unit model definition
}).ToList();
return query;
}
}
}
[Table("UnitTable")]
public class UnitModel
{
public String UnitID { get; set; }
public String UnitName { get; set; }
// other definitions
}
Controller
using ProjectName.Models;
[RoutePrefix("Input")]
public class InputController : Controller
{
[HttpGet]
public ActionResult Winner()
{
WinnerModel model = new WinnerModel()
{
// default values on first visit/reload page
TranDate = DateTime.Now.Date,
UnitList = new List<UnitModel>(); // list declaration
}
return View(model);
}
public PartialViewResult CustomerData(String customerId, String sessionId, DateTime tranDate, WinnerModel model)
{
if (DevExpressHelper.IsCallback && !String.IsNullOrEmpty(customerId))
{
Session["CustomerID"] = customerId;
Session["SessionID"] = sessionId;
Session["TranDate"] = Convert.ToDateTime(tranDate);
using (var DB = new DBContext())
{
var query = DB.Customers.Where(c => c.CustomerID == customerId).FirstOrDefault();
// model property assignments
}
}
return PartialView("_CustomerData", model);
}
public PartialViewResult ShowItemsGrid(WinnerModel model)
{
String customerId = (Session["CustomerId"] ?? String.Empty).ToString();
String sessionId = (Session["SessionId"] ?? String.Empty).ToString();
String lastCustomer = (Session["LastCustomer"] ?? String.Empty).ToString();
DateTime tranDate = Convert.ToDateTime(Session["TranDate"] ?? DateTime.Now.Date);
using (var DB = new DBContext())
{
model.CustomerId = customerId;
model.SessionId = sessionId;
model.TranDate = tranDate;
model.UnitList = model.GetUnitList(sessionId, tranDate);
if (model.UnitList == null || model.UnitList.Count == 0)
{
model.UnitList = new List<UnitModel>();
}
Session["LastCustomer"] = lastCustomer;
return PartialView("_GridView", model);
}
}
}
View (Winner.cshtml)
#using ProjectName.Models
#model WinnerModel
#Html.EnableUnobtrusiveJavascript()
<script type="text/javascript">
var customer = null;
function initializeGrid()
{
ItemsGrid.PerformCallback(); // routine check if customer name exists
}
function comboChanged(s, e) {
customer = s.GetValue();
CustomerDataPanel.PerformCallback(); // callback to fill customer data for partial view & load units into gridview
}
// callback to insert values into session variable
function customerBeginCallback(s, e) {
e.customArgs["customerId"] = customer;
e.customArgs["sessionId"] = SessionId.GetValue();
e.customArgs["tranDate"] = TranDate.GetValue();
}
function customerEndCallback(s, e) {
ItemsGrid.PerformCallback();
}
// count checked data inside gridview
// this may be asked on other context and doesn't matter for this one
function countUnits(buttonName, url)
{
// other code
}
</script>
#using (Html.BeginForm("Winner", "Input", FormMethod.Post))
{
Html.DevExpress().TextBoxFor(m => m.SessionId, TextBoxSettings).GetHtml();
Html.DevExpress().DateEditFor(m => m.TranDate, DateEditSettings).GetHtml();
// this combobox has client-side event SelectedIndexChanged = "comboChanged"
// GetCustomers method just populate customers data into combobox and unrelated to this problem
Html.DevExpress().ComboBoxFor(m => m.CustomerId, ComboBoxSettings).BindList(ProjectName.Providers.GetCustomers()).GetHtml();
Html.RenderPartial("_CustomerData", Model); // DX callback panel
Html.RenderPartial("_GridView", Model);
// button to count all checked values inside gridview
Html.DevExpress().Button(CountButtonSettings).GetHtml();
Html.DevExpress().LabelFor(m => m.TotalPrice, PriceLabelSettings).GetHtml();
// button for submit & reset form here
Html.DevExpress().Button(SubmitButtonSettings).GetHtml();
Html.DevExpress().Button(ResetButtonSettings).GetHtml();
}
Partial View (_CustomerData.cshtml)
#using ProjectName.Models
#model WinnerModel
#{
// MVC DX callback panel for customer details
// Name = CustomerDataPanel
// CallbackRouteValues: Controller = Input, Action = CustomerData
// ClientSideEvents.BeginCallback = customerBeginCallback
// ClientSideEvents.EndCallback = customerEndCallback
Html.DevExpress().CallbackPanel(CallbackPanelSettings).GetHtml();
}
Partial View (_GridView.cshtml)
#using ProjectName.Models
#model WinnerModel
#{
// MVC DX GridView with row selection checkboxes
// The gridview column structure is exactly same as UnitModel has
// Name = ItemsGrid
// CallbackRouteValues: Controller = Input, Action = ShowItemsGrid
// ClientSideEvents.Init = initializeGrid
GridViewExtension grid = Html.DevExpress().GridView(GridViewSettings);
grid.Bind(Model.UnitList).GetHtml(); // grid bound to List<UnitModel>
}
All gridview changes require sufficent privileges (i.e. admin/supervisor).
Problem Statement
I want anyone help finding out where and how proper routine codes to empty gridview data must be attached on controller method(s) to give expected results. As I tried so far, the gridview still maintaining its previous state given from session variable when Winner page revisited or reloaded (immediate first visit after login worked because all session variables are empty, thus no data was populated to gridview).
Additionally, I want to show JS confirm message when user trying to close/reload Winner page while some/all gridview data are being checked.
Expected Results
For every first visit, revisit & reload on Winner page, the gridview content must empty.
After a user provides certain customer ID, the gridview will populated with some unit data from unit table, where changes inside it immediately lost when user accepts reloading/closing page confirm message.
Any kind of answers or suggestions will appreciated.
I would like to pass #survey which is object of class Survey to the JavaScript function SubmitClick and then to the SubmitSurvey in PersonController.cs
My button: when clicked it passes arguments to javascript:SubmitClick
<button class='mybutton' type='button' onclick="javascript:SubmitClick(#Model.Item1.Id, #survey);">Save Survey</button>
and JavaScript function:
function SubmitClick(pid, sid) {
var url = '#Url.Action("SubmitSurvey", "Person")';
$.post(url, { personId: pid, survey: sid }, function (data) {
alert('updated' + pid);
});
}
and method to which I want to pass #survey:
public void SubmitSurvey(int personId, Survey survey) {
}
The result is:
I want to point out that passing #survey.Id(int) worked so the only problem is passing the #survey.
Error pop ups at passing arguments to java script function.
EDIT
The button is inside foreach loop and the model is little bit complex. Can I just serialize it inside a loop?
I pass List of Survey to the view from here:
public ActionResult _Survey1(int id) {
System.Diagnostics.Debug.WriteLine("PASSED ID: " + id);
Person person = db.Persons.Find(id);
//Passing a Tuple to Partial View, I want to pass copies further I use copying constructor
List<Survey> localSurveysCopy = new List<Survey>();
foreach (Survey survey in db.Surveys) {
localSurveysCopy.Add(new Survey(survey));
}
var tuple = new Tuple<Person, List<Survey>>(person, localSurveysCopy) { };
return PartialView(tuple);
}
The view:
#using WebApplication2.Models
#model System.Tuple<Person, List<Survey>>
<hr />
<h1>Surveys</h1>
<input type="button" id="Coll" value="Collapse" onclick="javascript:CollapseDiv()" />
#{int i = 1;}
#foreach (var survey in Model.Item2) {
using (Html.BeginForm()) {
<h2>Survey #(i)</h2>
<p />
#Html.EditorFor(x => survey.Questions)
<button class='mybutton' type='button' onclick="javascript:SubmitClick(#Model.Item1.Id, #Newtonsoft.Json.JsonConvert.SerializeObject(survey));">Save Survey</button>
}
i++;
<hr style="background-color:rgb(126, 126, 126);height: 5px" />
}
<hr />
The script. I think I had to pass variable directly as I have many surveys and many buttons:
function SubmitClick(pid, sid) {
var url = '#Url.Action("SubmitSurvey", "Person")';
var objSurvey = $.parseJSON(sid);
$.post(url, { personId: pid, survey: objSurvey }, function (data) {
alert('updated person' + pid + ' survey ' + sid);
});
}
I get:
A first chance exception of type 'System.Web.HttpException' occurred in System.Web.dll
A first chance exception of type 'Newtonsoft.Json.JsonSerializationException' occurred in Newtonsoft.Json.dll
A first chance exception of type 'Newtonsoft.Json.JsonSerializationException' occurred in Newtonsoft.Json.dll
A first chance exception of type 'Newtonsoft.Json.JsonSerializationException' occurred in Newtonsoft.Json.dll
A first chance exception of type 'Newtonsoft.Json.JsonSerializationException' occurred in Newtonsoft.Json.dll
A first chance exception of type 'Newtonsoft.Json.JsonSerializationException' occurred in Newtonsoft.Json.dll
A first chance exception of type 'Newtonsoft.Json.JsonSerializationException' occurred in Newtonsoft.Json.dll
A first chance exception of type 'Newtonsoft.Json.JsonSerializationException' occurred in Newtonsoft.Json.dll
A first chance exception of type 'Newtonsoft.Json.JsonSerializationException' occurred in System.Web.Mvc.dll
A first chance exception of type 'Newtonsoft.Json.JsonSerializationException' occurred in System.Web.Mvc.dll
The class Survey looks like:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace WebApplication2.Models {
public class Survey {
public int Id { set; get; }
public virtual ICollection<Question> Questions { set; get; }
public Survey() { }
public Survey(Survey survey) {
Id = survey.Id;
Questions = new List<Question>();
System.Diagnostics.Debug.WriteLine("SURVEY " + survey.Questions == null);
foreach (Question question in survey.Questions) {
Questions.Add(new Question(question));
}
}
}
public class Question {
public int Id { set; get; }
public string QuestionText { set; get; }
public virtual ICollection<Answer> Answers { set; get; }
public virtual Survey Survey { get; set; }
public string SelectedAnswer { set; get; } //this field is SET after clicking SAVE button
public Question() { }
public Question(Question question) {
Id = question.Id;
QuestionText = question.QuestionText;
Answers = question.Answers;
Survey = question.Survey;
SelectedAnswer = "";
}
}
public class Answer {
public int Id { set; get; }
public string AnswerText { set; get; }
public virtual Question Question { get; set; }
public virtual ICollection<Person> Persons { get; set; }
}
}
You cannot just pass C# object to JS and post it back.
You should:
Convert your object to JSON and pass it to JS. I advise to use Newtonsoft.JSON for it.
controller:
string json = JsonConvert.SerializeObject(survey);
markup:
<button class='mybutton' type='button' onclick="javascript:SubmitClick(#Model.Item1.Id, #json);">Save Survey</button>
Then from JS you should post JSON to your MVC controller and MVC will deserialize it your C# object.
markup:
function SubmitClick(pid, sid) {
var objSurvey = $.parseJSON(sid);
var url = '#Url.Action("SubmitSurvey", "Person")';
$.post(url, { personId: pid, survey: objSurvey }, function (data) {
alert('updated' + pid);
});
}
controller:
public void SubmitSurvey(int personId, Survey survey) { }
UPDATED:
Your Survey entity cannot be serialized correctly because of cycle references between classes. So you have few options here:
use [JsonIgnore] attribute to ignore backreferences. (So you should mark Survey property inside Question class with this attribute, Question property inside Answer class and so on) Please keep in mind that these fields will be not serialized to JS and deserialized back to C# objects.
create separate model without cycle references for serialization and use it when convert to JSON.
You are doing it wrong.
Basically when you do #survey, you are looking at a server side code. At the client side, this #survey, which is an instance of a strongly typed clr class, is converted to string, and you know what happens when you convert and object to string, you get its Type in string i.e
#survey.ToString() == "WebApplications2.Models.Survey"
obviously it is wrong cause, your button tag's markup, at the end, effectively becomes :
<button class='mybutton' type='button'
onclick="javascript:SubmitClick(#Model.Item1.Id,
WebApplications2.Models.Survey);">
Save Survey
</button>
You should basically first serialize your #survey object at the server side and store it in a hidden variable i.e.
#Html.Hidden("hdnSurvey", Newtonsoft.Json.JsonConvert.SerializeObject(Model))
and use this hidden variable inside your javascript
i.e.
function SubmitClick(pid) {
var objSurvey = $.parseJSON( $('#hdnSurvey').val());
var url = '#Url.Action("SubmitSurvey", "Person")';
$.post(url, { personId: pid, survey: objSurvey }, function (data) {
alert('updated' + pid);
});
}
Sending back the #survey variable is pointless, the changes from the UI will not be reflected from the variable, but from HTML input, what you really need is serializing the form.
Here is a complete solution for what you really need.
Model
public class Person
{
public int Id { set; get; }
}
public class Survey
{
public int Id { set; get; }
public virtual ICollection<Question> Questions { set; get; }
}
public class Question
{
public int Id { set; get; }
public string QuestionText { set; get; }
public virtual ICollection<Answer> Answers { set; get; }
public int SelectedAnswerId { set; get; } // Notice that I change it into int not string
}
public class Answer
{
public int Id { set; get; }
public string AnswerText { set; get; }
}
Controller
public ActionResult Index()
{
var person = new Person { Id = 1 };
var survey = new Survey
{
Id = 12,
Questions = new List<Question>
{
new Question
{
Id = 34,
QuestionText = "What is your favorite language?",
Answers = new List<Answer>
{
new Answer { Id = 56, AnswerText = "A#" },
new Answer { Id = 57, AnswerText = "B#" },
new Answer { Id = 58, AnswerText = "C#" }
}
}
}
};
var model = new Tuple<Person, List<Survey>>(person, new List<Survey> { survey });
return View(model);
}
[HttpPost]
public ActionResult SubmitSurvey(int personId, Survey survey)
{
return Json(new { success = true });
}
Index.cshtml
#model Tuple<Person, List<Survey>>
#{
ViewBag.Title = "Index";
}
<h2>Surveys</h2>
#{int i = 1;}
#foreach (var survey in Model.Item2)
{
using (Html.BeginForm())
{
<h3>Survey #(i++)</h3>
#Html.HiddenFor(x => survey.Id)
#Html.EditorFor(x => survey.Questions)
<button class="mybutton" type="button">Save Survey</button>
}
}
#section Scripts
{
<script>
$(".mybutton").click(function () {
var personId = "#Model.Item1.Id";
var survey = $(this).closest("form").serialize();
var data = survey + "&personId=" + personId;
$.ajax({
type: "POST",
url: "#Url.Action("SubmitSurvey", "Survey")",
data: data,
traditional: true,
success: function (data) {
alert("submitted :" + data.success);
}
});
});
</script>
}
EditorTemplates/Question.cshtml
#model Question
<h3>#Model.QuestionText </h3>
#Html.HiddenFor(x => x.Id)
#foreach (var a in Model.Answers)
{
<label>#Html.RadioButtonFor(b => b.SelectedAnswerId, a.Id) #a.AnswerText</label>
}
Result
If the user selected B# on the first survey on the first question, the submitted survey will return SelectedAnswerId as 57. The other properties like Answers and QuestionText are null and they're not important for saving so let it be.
I have this modelView
public class Ue
{ public class uEkranModel
{
public List<Grup> Grup = new List<Grup>();
private List<Secim> _secim;
public List<Secim> secim
{
get
{
if (_secim == null)
_secim = new List<Secim>();
return _secim;
}
set { _secim = value; }
}
}
public class Secim
{
public Guid uGuid { get; set; }
public Guid fGuid { get; set; }
}
}
I need to fell the List secims items with JS and post it back to controller.
I have tried to :
1)initialize the list in the controller :
Controller :
gidecek.Data = new Models.Ucak.UcakDeneme.uEkranModel();
gidecek.Data.secim.Add(new Models.Ue.Secim { uGuid = new Guid() });
gidecek.Data.secim.Add(new Models.Ue.Secim { uGuid = new Guid() });
View :
#using (Html.BeginForm("deneme", "U", FormMethod.Post, new { id = "secimTamam", style = "display:none" }))
{
#Html.EditorFor(m => m.Data.secim[0])
#Html.TextBoxFor(m => m.Data.secim[0].uGuid, new {id="gidis" })
}
JS :
$("#Data_secim_0__ucusGuid").attr("value", index);
This way , when the code is executed the value field of the textboxfor is changed(when the JS fired) but when I check the post data in controller , it is NULL.
also tried :
$("#Data_secim_0__ucusGuid").val(index);
which doesnt cahnge the value of teh textbox.
What I need is to fill the model values with js and post the form with js as well.(The data user is selecting is different, I am just posting back the GUID of the items within a form.)
2 possible issues. Your getter is initializing a new List<Secim>. Try initializing it in the constructor
public class uEkranModel
{
public uEkranModel()
{
secim = new List<Secim>();
}
public List<Secim> secim { get; set;}
....
}
Also I have seen other posts on SO indicating problems posting back GUID's (and one solution that was accepted was to use a view model with the GUID's converted to strings)