Object not added to collection - ajax

I have this model:
public class QuestionDTO
{
public Question Question { get; set; }
public OpenQuestionAnwser OpenQuestionAnwser { get; set; }
public List<ChoiceQuestionAnwser> ChoiceQuestionAnwsers { get; set; }
public void AddChoiceQuestionAnwser()
{
ChoiceQuestionAnwsers.Add(new ChoiceQuestionAnwser() {ChoiceQuestionAnwserID = ChoiceQuestionAnwsers.Count});
}
public void RemoveChoiceQuestionAnwser(int index)
{
ChoiceQuestionAnwsers.RemoveAt(index);
}
public void Save()
{
}
}
and I want to create an ajax form to dynamically add objects to a collection, but I have problem because when I send the form to the server I get an empty collection. I tried a few different ways but with no luck.
Form code:
#using (Ajax.BeginForm("AddChoiceQuestionAnwser","Question",new AjaxOptions
{
UpdateTargetId = "chooseAnwsersTableBody"
}))
{
<table class="hovered" id="anwsers">
<tr>
<th>Poprawna</th>
<th>Treść odpowiedzi</th>
<th></th>
</tr>
<tbody id="chooseAnwsersTableBody">
#Html.Partial("ChooseAnwsersView",Model)
</tbody>
</table>
#Html.HiddenFor(a => a.ChoiceQuestionAnwsers);
#Html.HiddenFor(a => a.OpenQuestionAnwser)
#Html.HiddenFor(a => a.Question)
<div>
<input type="submit" value="Dodaj odpowiedź"/>
</div>
}
and controller code:
[HttpPost]
public ActionResult AddChoiceQuestionAnwser(QuestionDTO questionDto)
{
questionDto.AddChoiceQuestionAnwser();
return PartialView("ChooseAnwsersView", questionDto);
}
and partial view
#model BusinessLogic.DTO.Test.QuestionDTO
#{
ViewBag.Title = "ChooseAnwsersView";
}
#foreach(var item in Model.ChoiceQuestionAnwsers)
{
<tr>
<td> #Html.CheckBox("ChoiceQuestionAnwsers["+item.ChoiceQuestionAnwserID+"].IsCorrect",item.IsCorrect,new {#id="ChoiceQuestionAnwsers_"+item.ChoiceQuestionAnwserID+"__IsCorrect"})
#Html.Hidden("ChoiceQuestionAnwsers[" + item.ChoiceQuestionAnwserID + "].ChoiceAnwserType", item.ChoiceAnwserType, new { #id = "ChoiceQuestionAnwsers_" + item.ChoiceQuestionAnwserID + "__ChoiceAnwserType" })
#Html.Hidden("ChoiceQuestionAnwsers[" + item.ChoiceQuestionAnwserID + "].ChoiceQuestionAnwserID", item.ChoiceQuestionAnwserID, new { #id = "ChoiceQuestionAnwsers_" + item.ChoiceQuestionAnwserID + "__ChoiceQuestionAnwserID" })
#Html.Hidden("ChoiceQuestionAnwsers[" + item.ChoiceQuestionAnwserID + "].Data", item.Data, new { #id = "ChoiceQuestionAnwsers_" + item.ChoiceQuestionAnwserID + "__Data" })
#Html.Hidden("ChoiceQuestionAnwsers[" + item.ChoiceQuestionAnwserID + "].Question", item.Question, new { #id = "ChoiceQuestionAnwsers_" + item.ChoiceQuestionAnwserID + "__Question" })
#Html.Hidden("ChoiceQuestionAnwsers[" + item.ChoiceQuestionAnwserID + "].QuestionID", item.QuestionID, new { #id = "ChoiceQuestionAnwsers_" + item.ChoiceQuestionAnwserID + "__QuestionID" })
</td>
<td>#Html.Editor("ChoiceQuestionAnwsers[" + item.ChoiceQuestionAnwserID + "].Text", item.Text, new { #id = "ChoiceQuestionAnwsers_" + item.ChoiceQuestionAnwserID + "__Text" })
</td>
<td><a href='#' data-bind='click: $root.removeGift'>Usuń</a></td>
</tr>
}
Can anybody help me?

Try strong typing the form:
#for (int i = 0; i < Model.ChoiceQuestionAnwsers.Count; i++)
{
#Html.CheckBoxFor(m => m.ChoiceQuestionAnwsers[i].IsCorrect)
...
}
Inside your partial view.

Related

Posting dynamic table using ASP.NET Core MVC

I'm reading data from new tables using a SQL returning a datatable and able to show it in a view using the datatable as a model but the post/submit does not return anything, except in the HttpContext.Request.Form.
The new table column names cannot be determined except using SQL, so cannot use a model
// GET: /Home/
public async Task<IActionResult> Edit()
{
var conn = _context.Database.GetDbConnection();
await conn.OpenAsync();
var command = conn.CreateCommand();
command.CommandText = "SELECT * FROM NewTable";
var reader = await command.ExecuteReaderAsync();
DataTable dt = new DataTable();
dt.Load(reader);
dt.PrimaryKey = new DataColumn[]
{
dt.Columns["id"],
dt.Columns["idd"],
dt.Columns["idf"]
};
return View(dt);
}
#using System.Data
#model DataTable
#{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Edit</title>
</head>
<body>
<form asp-controller="Dynam" asp-action="Edit" method="post">
<table>
<tr>
#foreach (System.Data.DataColumn column in Model.Columns)
{
<td>#column.ColumnName</td>
}
</tr>
#for (var i = 0; i < Model.Rows.Count; i++)
{
var row = Model.Rows[i];
<tr>
#foreach (System.Data.DataColumn column in Model.Columns)
{
if (column.ColumnName == "id")
{
#Html.Hidden(column.ColumnName, row[column.ColumnName] )
}
else
{
<td>#Html.TextBox(column.ColumnName + "[" + i.ToString() + "]", row[column.ColumnName])</td>
}
}
</tr>
}
</table>
<div class="form-group">
<button type="submit" value="save" class="btn btn-default">Submit</button>
</div>
</form>
<div></div>
</body>
</html>
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(DataTable dt)
{
var commandText = "UPDATE MyTable SET #NewColumn = ('123xyz') " +
"WHERE Id = #Id AND Idd = #Idd AND Idf = #IDF";
var first = true;
foreach (string key in HttpContext.Request.Form.Keys)
{
// build sql for update
For example I create a model like this
using System.Collections.Generic;
namespace WebMvcApp.Models
{
public class DynamicTable
{
public string name { get; set; }
public List<Dictionary<string, string>> properties { get; set; }
}
}
I set all the rows as a List and all of the Column as a Dictionary. Then I create a test data like this:
public IActionResult Index()
{
var map1 = new Dictionary<string, string> {
{ "key1", "valueA1" },
{ "key2", "valueA2" },
{ "key3", "valueA3" }
};
var map2 = new Dictionary<string, string> {
{ "key1", "valueB1" },
{ "key2", "valueB2" },
{ "key3", "valueB3" }
};
var table = new List<Dictionary<string, string>>
{
map1,
map2
};
var entity = new DynamicTable
{
name = "table1",
properties = table
};
return View(entity);
}
Then I can deal with it in my view like this:
#model DynamicTable
<table>
<tr>
#foreach (var entry in Model.properties[0])
{
<td>#entry.Key</td>
}
</tr>
#{
foreach (var item in Model.properties)
{
<tr>
#foreach(var keypair in item)
{
<td>#keypair.Value</td>
}
</tr>
}
}
</table>

MVC3 Razor check box values are not coming through on submit

I have a form with serval check box items in a list.
I have a editor for this list. They display on the screen fine.
But when submitted the items checked are not submitted in the model...
Models:
public class ContactUsersModel : BaseModel
{
public IList<FilterCheckModel> PreviousVisitors { get; set; }
}
public class FilterCheckModel : BaseModel
{
public string Name { get; set; }
public string Value { get; set; }
public bool IsChecked { get; set; }
}
Controller:
IList<FilterCheckModel> prevVisitList = new List<FilterCheckModel>();
prevVisitList.Insert(0, new FilterCheckModel() { Name = "All previous visitors", Value = "0" });
prevVisitList.Insert(1, new FilterCheckModel() { Name = "Not visited in last month", Value = "1" });
prevVisitList.Insert(2, new FilterCheckModel() { Name = "Not visited for 1-3 months", Value = "2" });
prevVisitList.Insert(3, new FilterCheckModel() { Name = "Not visited for 3-6 months", Value = "3" });
prevVisitList.Insert(4, new FilterCheckModel() { Name = "Not visited for over 6 months", Value = "4" });
model.PreviousVisitors = prevVisitList;
html:
<table>
<tr>
<th>
Previous visitors:
</th>
</tr>
#for (int i = 1; i < Model.PreviousVisitors.Count; i++)
{
#Html.EditorFor(model => model.PreviousVisitors[i], "FilterCheck", new { Index = i + 1})
}
</table>
editor:
<tr>
<td>
#Model.Name
</td>
<td>
#Html.CheckBoxFor(x => x.IsChecked)
#Html.HiddenFor(x => x.Value)
</td>
</tr>
Found it!
the reason was that in my loop i was started i = 1.
this causes an issue for some reason.
The index need to start form 0...
#for (int i = 1; i < Model.PreviousVisitors.Count; i++)
so i changed this to
#for (int i = 0; i < Model.PreviousVisitors.Count; i++)
and it worked!

how to delete an Uploaded file from the server?

Hi all I have an upload function where users can upload the files and I show the uploaded files in a table before inserting in DB and I give an delete option in the table if user wants delete any uploaded file he dsnt want..I am trying this code but, the files are not getting deleted
this is my file upload code
public ActionResult UploadFile(string AttachmentName, BugModel model)
{
BugModel bug = null;
if (Session["CaptureData"] == null)
{
bug = model;
}
else
{
bug = (BugModel)Session["CaptureData"];
}
foreach (string inputTagName in Request.Files)
{
HttpPostedFileBase file1 = Request.Files[inputTagName];
if (file1.ContentLength > 0)
{
BugAttachment attachment = new BugAttachment();
var allowedExtensions = new[] { ".doc", ".xlsx", ".txt", ".jpeg", ".docx" };
var extension = Path.GetExtension(file1.FileName);
if (!allowedExtensions.Contains(extension))
{
model.ErrorMessage = "{ .doc, .xlsx, .txt, .jpeg }, files are allowed.... ";
}
else
{
string filename = Guid.NewGuid() + Path.GetFileName(file1.FileName);
string path = "/Content/UploadedFiles/" + filename;
string savedFileName = Path.Combine(Server.MapPath("~" + path));
file1.SaveAs(savedFileName);
attachment.FileName = "~" + path.ToString();
attachment.AttachmentName = AttachmentName;
attachment.AttachmentUrl = attachment.FileName;
bug.ListFile.Add(attachment);
model = bug;
}
Session["CaptureData"] = model;
}
}
ModelState.Clear();
return View("LoadBug", bug);
}
this is my view for showing the uploaded files in a table
<table align="center" class="gridtable" border="0" cellspacing="0" cellpadding="0">
<tr>
<th>
Attachment Name
</th>
<th>
Attachment Url
</th>
<th>
Action
</th>
</tr>
<% if (Model != null && Model.ListFile != null)
{ %>
<% foreach (var Emp in Model.ListFile)
{ %>
<tr class="Data">
<td >
<%:Emp.AttachmentName %>
</td>
<td >
<%: Emp.FileName %>
</td>
<td>
<%-- <%= Html.ActionLink("Delete", "Delete")%>--%>
<%:Html.ActionLink("Delete", "Delete", new { #FileName = Emp.FileName })%>
</td>
</tr>
<% } %>
<% } %>
</table>
and this is my delete code
public ActionResult Delete(string FileName)
{
char DirSeparator = System.IO.Path.DirectorySeparatorChar;
string FilesPath = ";" + FileName;
string filenameonly = name + Path.GetFileName(FilesPath);
string FPath = "Content" + DirSeparator + "UploadedFiles" + DirSeparator + filenameonly;
// Don't do anything if there is no name
if (FileName.Length == 0) return View();
// Set our full path for deleting
string path = FilesPath + DirSeparator;
// Check if our file exists
if (System.IO.File.Exists(Path.GetFullPath(AppDomain.CurrentDomain.BaseDirectory + FPath)))
{
// Delete our file
System.IO.File.Delete(Path.GetFullPath(AppDomain.CurrentDomain.BaseDirectory + FPath));
}
return View("LoadBug", Bug);
}
public string name { get; set; }
public object Bug { get; set; }
}

Validation Issues on Hidden DropDownListFor's ASP.NET MVC3

FINAL EDIT: The problem was that ViewBag.PropName == Model.PropName;
FIX: ViewBag.PropName ===> ViewBag.PropName2
This is my first time posting; I'm new and think I messed up the layout... so sorry!
I encountered some issues with client-side validation for hidden dropdownlistfor's.
I am working with ASP.NET MVC3 and have a lot of hidden ddl on this page.
The validation however, doesn't work for some ddl's.
Has anyone ever had a problem with this before?
These are 2 properties; 1 working, 1 failing
//VALIDATION FAILS
[Required]
[Range(0, 4)]
public int TiresBack { get; set; }
//VALIDATION WORKS
[Required]
[Range(0, 4)]
public int TechnicalState { get; set; }
This is a piece the razor:
<tr>//THIS DOESN'T WORK
<td style="width: 38%;">
#txtFor("tiresBack")
</td>
//This is JQuery Star-Rating.
<td align="center" id="starsTiresBack">
</td>
<td>
#Html.DropDownListFor(model => model.TiresBack, ViewBag.TiresBack as IEnumerable<SelectListItem>, new { style = "display:none;" })
<input class="blueButton" type="button" id="btnBrandRearTires" value="#txtFor("brandTiresBack")" />
<span>#Html.ValidationMessageFor(model => model.TiresBack)</span> <span>#Html.ValidationMessageFor(model => model.BrandRearTires)</span>
</td>
</tr>
//THIS WORKS
<tr>
<td style="width: 38%;">
#txtFor("technicalState")
</td>
<td id="starsTechnicalState" align="center">
</td>
<td>
#Html.DropDownListFor(model => model.TechnicalState, ViewBag.TechState as IEnumerable<SelectListItem>, new { style = "display:none;" })
<input class="blueButton" type="button" id="btnTechnicalStateDescription" value="#txtFor("technicalStateDescriptionButton")" style="display:none;"/>
<span>#Html.ValidationMessageFor(model => model.TechnicalState)</span> <span>#Html.ValidationMessageFor(model => model.TechnicalStateDescription)</span>
</td>
</tr>
EDIT1: Initialised in the controller using this method:
public static List<SelectListItem> CreateDefaultStateList(int? selected = -1)
{
List<SelectListItem> sl = new List<SelectListItem>();
for (int i = -1; i < 5; i++)
{
SelectListItem sli = new SelectListItem();
if (i == 0 || i == -1)
sli.Text = "";
else
sli.Text = i.ToString();
sli.Value = i.ToString();
if (i == selected)
sli.Selected = true;
sl.Add(sli);
}
return sl;
}
EDIT2: The create controller. defaultstatelist is what got returned from the method posted above.
List<SelectListItem> defaultStateList = CreateDefaultStateList();
[Authorize]
public ActionResult Create()
{
FillViewBag();
ViewBag.PropX = defaultStateList;
ViewBag.TiresFront = defaultStateList;
ViewBag.TechState = defaultStateList;
ViewBag.PropY= defaultStateList;
ViewBag.PropZ= defaultStateList;
ViewBag.PropA= defaultStateList;
ViewBag.PropB= defaultStateList;
ViewBag.PropC= defaultStateList;
ViewBag.PropD= defaultStateList;
return View();
}
Typing this I notice the the default value in the method. That could be it...
==> Tried it, wasn't it. Updated code to '-1' as default value now.
The problem was that ViewBag.PropName == Model.PropName;
FIX: Rename ViewBag.PropName to something else like ViewBag.PropName2.

how to get label value in mvc 3?

In Model:
public class DataViewModel
{
public IList<RowsCollection> Rows { get; set; }
public PaiementMethod PaiementMethod { get; set; }
}
public class RowsCollection
{
public string ID { get; set; }
public string Question { get; set; }
}
public enum PaiementMethod
{
Cash,
CreditCard,
}
In the Controller - Index ActionResult I have return my Model and render its into view page something like :
#model WebNexpo.Controllers.DataViewModel
#using (Html.BeginForm("Save", "page", FormMethod.Post, new { id = "saves"}))
{
foreach (var item in Model.Rows)
{
#Html.Label(item.Question)
<label for="paiement_cash">
Cash</label>
#Html.RadioButtonFor(m => m.PaiementMethod, "Cash", new { name = "paiement_cash" + #item.ID + "", id = "radioID" + #item.ID + "", Group = "Group" + #item.ID + "" })
<label for="paiement_cc">
Credit card</label>
#Html.RadioButtonFor(m => m.PaiementMethod, "CreditCard", new { name = "paiement_cc" + #item.ID + "", id = "radioname" + #item.ID + "", Group = "Group" + #item.ID + "" })
}
<input id="Saveser" type="submit" value="" class="button1" />
}
in submit form Action Event :
[HttpPost]
public ActionResult Save(DataViewModel model)
{
if (ModelState.IsValid)
{
//want to read all the label which selected rediobutton.
means suppose 4 question render on page and user have selected only 2
question of the answer.so How can accomplish here?
}
return RedirectToAction("Index", new {value = "123"});
}
There's some inconsistency here. You are rendering 2 radio buttons for each row so you probably want to reorganize your view model into:
public class DataViewModel
{
public IList<RowsCollection> Rows { get; set; }
}
public class RowsCollection
{
public string ID { get; set; }
public string Question { get; set; }
public PaiementMethod PaiementMethod { get; set; }
}
and then:
#model DataViewModel
#using (Html.BeginForm("Save", "page", FormMethod.Post, new { id = "saves"}))
{
for (var i = 0; i < Model.Rows.Count; i++)
{
<div>
#Html.HiddenFor(x => x.Rows[i].ID)
#Html.LabelFor(x => x.Rows[i].Question)
#Html.EditorFor(x => x.Rows[i].Question)
#Html.Label("payment_cash" + i, "Cash")
#Html.RadioButtonFor(m => m.Rows[i].PaiementMethod, "Cash", new { id = "payment_cash" + i })
#Html.Label("payment_cc" + i, "Credit card")
#Html.RadioButtonFor(m => m.Rows[i].PaiementMethod, "CreditCard", new { id = "payment_cc" + i })
</div>
}
<input id="Saveser" type="submit" value="" class="button1" />
}
and finally:
[HttpPost]
public ActionResult Save(DataViewModel model)
{
if (ModelState.IsValid)
{
// model.Rows[0].PaiementMethod will contain the selected payment method for the first question
// model.Rows[1].PaiementMethod will contain the selected payment method for the second question
// ...
}
return RedirectToAction("Index", new { value = "123" });
}
or if you want a single payment method you could keep your view model as is but then leave the radio buttons outside of the loop in your view. Like that:
#using (Html.BeginForm("Save", "page", FormMethod.Post, new { id = "saves" }))
{
for (var i = 0; i < Model.Rows.Count; i++)
{
<div>
#Html.HiddenFor(x => x.Rows[i].ID)
#Html.LabelFor(x => x.Rows[i].Question)
#Html.EditorFor(x => x.Rows[i].Question)
</div>
}
#Html.Label("payment_cash", "Cash")
#Html.RadioButtonFor(x => x.PaiementMethod, "Cash", new { id = "payment_cash" })
#Html.Label("payment_cc", "Credit card")
#Html.RadioButtonFor(x => x.PaiementMethod, "CreditCard", new { id = "payment_cc" })
<input id="Saveser" type="submit" value="" class="button1" />
}

Resources