I'm working in MVC and was trying to use jquery to perform the following, if there is an easier way i'd be happy to hear it...
I'm looking to have my form create dynamic input to produce something for example that could look like this: *i won't know how many subcat's they are going to enter nor how many main categories.
category0 <btnInsertSubCat0>
subcat0.0
subcat0.1
subcat0.2
category1 <btnInsertSubCat1>
subcat1.0
subcat1.1
<btbInsertNewCat>
I can produce a button that appends textboxes one after another as well as a button next to it but even if I use the .live attribute I can't get the subcat button to fire. Changed code around a lot and looked at different tutorial to no avail, fig. this would be semi easy to do?
jQuery(document).ready(function () {
var procID = 0;
var orgID = 0;
$('.clickme').live('click', function () {
var newItem = $("<input type='text' name='Procedure[" + procID + "]' value='Procedure[" + procID + "] />");
var newLabel = $("<br /><label id='Label[" + procID + "]' >ProcedureID: [" + procID + "]</label>");
var newDiv = $("<div class='objective'><b>Insert Objective</b>[" + procID + "." + orgID + "]</div>");
$("#procedureHolder").append(newLabel);
$("#procedureHolder").append(newItem);
$("#procedureHolder").append(newDiv);
procID++;
});
$('.objective').live('click', function () {
var newObj = $("<input type='text' id='Objective[" + (procID - 1) + "." + orgID + "]' >ObjectiveID: [" + (procID - 1) + "." + orgID + "]</label>");
$("#procedureHolder").append(newObj);
orgID++;
});
});
I edited my post, figured it out on my own how to utilize jquery to create an unlimited number of child dynamic textboxes. They all post back in the form collection as well. I figured out why the objectives weren't showing up, turns out i was declaring ID rather than Name. Thanks!
I've used the following approach for a dynamic search screen using ASP.NET MVC. Search options where managed in a database mapped to a product. This allowed the marketing team to tweak searching results and the search options in the admin section of the website. Essentially the approach was the following:
public class FormFieldCollection : List<FormField>
{
public string FormFieldType { get; set; }
}
public class FormField
{
public string Name {get;set;}
public string Type {get;set;}
public string Value {get;set;}
public bool IsChecked {get;set;}
}
public class FormFieldModel
{
public FormFieldCollection PaymentOptions { get; set; }
}
In the view generated from either custom Helper or use a foreach.
In your Controller action something like:
public ActionResult SomeActionMethod(FormCollection formCollection)
{
//search through the results, map back to class or loop through key value pairs.
}
View Code, obviously include some nice html markup to format the form.
#Model FormFieldCollection
#{
View.Title = "Form";
Layout = "~/Views/Shared/_defaultMaster.cshtml";
}
#foreach(var formField in Model){
<input type="#formField.Type" id="#formField.Name" name="#formField.Name" value=""#formField.Value"" />
}
#using (Html.BeginForm("SomeActionMethodAdd", "ControllerName", FormMethod.Post))
{
//Submit form to
Field Name: <input type="text" value="" /> * must be unique
<input type="submit" value="Submit" />
}
Syntax mightn't be perfect just going of memory for razor.
Related
I have 3 models - School, Classrooms & Courses.
A school can have many classrooms, and a classroom can have many courses taught in it.
public class School
{
public int SchoolId { get; set; }
public string SchoolName { get; set; }
public List<Classroom> Classrooms { get; set; }
}
public class Classroom
{
public int ClassroomId { get; set; }
public string Room { get; set; }
public List<Course> Courses { get; set; }
public virtual int SchoolId { get; set; }
}
public class Course
{
public int CourseId { get; set; }
public string CourseName { get; set; }
public virtual int ClassroomId { get; set; }
}
I want to create CRUD actions for School, where I can add 0 to many classrooms and within each classroom create 0 to many courses all in one form. Allowing the user to dynamically add classrooms and courses within those classrooms all within creating a school
The way that I'm accomplishing this right now is hard coding (where School is the #Model):
<div class="col-md-10">
<input asp-for="#Model.SchoolName" class="form-control" />
</div>
<div class="col-md-10">
<input asp-for="#Model.Classroom[0].Room" class="form-control" />
</div>
<div class="col-md-10">
<input asp-for="#Model.Classroom[0].Course[0].CourseName" class="form-control" />
</div>
<div class="col-md-10">
<input asp-for="#Model.Classroom[0].Course[1].CourseName" class="form-control" />
</div>
<div class="col-md-10">
<input asp-for="#Model.Classroom[0].Course[3].CourseName" class="form-control" />
</div>
I want the user to be able to add more classrooms and more courses or have the ability to remove them dynamically on the form.
You can use a partial view and JQuery to create dynamic rows in an html table.
I had a asset transfer form that required at least one line item. I placed a select list for the assets and a button to add the asset and it's details (the line item) to an html table via a partial view.
Partial View
#model ITFixedAssets.Models.TransferLineItem
#{//this helps with naming the controls within the main view/page
Models.TransferLineItem TransferLineItem = new Models.TransferLineItem();
}
<tr>
<td>
<span class="glyphicon glyphicon-trash" style="padding-right:5px;" data-action="removeItem" onclick="RemoveRow(this);"></span>
</td>
<td>
<label asp-for="#TransferLineItem.Id" class="form-control" id="row" style="height:34px;margin-top:5px;"></label>
</td>
<td>
<input asp-for="#TransferLineItem.Asset" class="form-control" />
</td>
<td>
<select asp-for="#TransferLineItem.Condition" class="form-control">
<option>Please Select</option>
<option value="New">New</option>
<option value="Good">Good</option>
<option value="Bad">Bad</option>
</select>
<span asp-validation-for="#TransferLineItem.Condition" class="text-danger"></span>
</td>
<td>
<input asp-for="#TransferLineItem.AssetDescription1" class="form-control" value="#ViewBag.AssetDescription1" />
</td>
<td>
<input asp-for="#TransferLineItem.AssetDescription2" class="form-control" />
</td>
<td>
<input asp-for="#TransferLineItem.InventoryNum" class="form-control" />
</td>
<td>
<input asp-for="#TransferLineItem.SerialNumber" class="form-control" />
</td>
</tr>
When the 'Add Asset' button is clicked it calls a JS function, which uses an ajax GET to run a 'code behind' function that returns the partial view, which is basically a skeleton of a row to be placed into the html table.
JS Function and 'Code Behind' function that returns the partial view.
function AddRow() {
$.ajax({
type: "GET",
url: "Create?handler=AddLineItemRow"
}).success(function (data) {
AddNewRow(data);
});
}
public PartialViewResult OnGetAddLineItemRow()
{
PartialViewResult partialViewResult = new PartialViewResult();
partialViewResult.ViewName = "_LineItem";
return partialViewResult;
}
If successful then the partial view ('data') is passed to another JS function that adds the row to the table and alters the generic id's and names of the controls to the appropriate 'array' style that is needed when the form is submitted in order to save the line items into the database.
//appends the transfer line item table with a new row (partial view)
function AddNewRow(data)
{
//******************************************************
//*************add the new to the table**********************
//append the table with the new row
$('#LineItems').append(data);
//******************************************************
//get value of asset drop down
var asset = $("#assetList").val();
//******************************************************
//*****add the row number to the id values of the controls********
//get the length of the table for new row #
//(subtract 1, not sure why unless it's adding the headers into the count)
var rowNum = $("#LineItems tr").length - 1;
//build new name to add to the controls
var nameIndex = rowNum - 1;
var newName = "[" + nameIndex + "].";
//get the row label
var lblRow = $("#row");
//create new id for the row label
var newId = "row_" + rowNum;
//apply new id
lblRow.attr("id", newId);
//get the last row in the table
var lastRow = $("#LineItems").find("tr").last();
////format id values for the input controls
//and add names for the controls
lastRow.find("input").each(function () {
// get id of this input control
var ctrl = $(this).attr("id");
//concatenate the row number to the id
var newId = ctrl + "_" + rowNum;
//assign new id to control
$(this).attr("id", newId);
//add the index to the control'
$(this).attr("name",$(this).attr("name").replace(".", newName));
});
//update the select list (for condition) id value
var selectControl = lastRow.find("select");
//get id of the select control
var scId = selectControl.attr("id");
//concatenate the row number to the id
newId = scId + "_" + rowNum;
//assign new id to control
selectControl.attr("id", newId);
//add new name to control
selectControl.attr("name", selectControl.attr("name").replace(".", newName));
//this ajax calls the function 'OnGetPopulateLineItemRow' in the code behind
//and passes the asset # and row # as parameters. the success function
//receives the return value from the OnGetPopulateItemRow function and
//passes that 'data' to the PopulateRow function below
$.ajax({
type: "GET",
url: "Create?handler=PopulateLineItemRow",
data: { _asset: asset },
//data: { _asset: asset, row: rowNum }
dataType: 'json',
success: function (data) {
PopulateRow(asset, data, rowNum);
}
});
}
After the new row has been added to the table and the names and id's are changed, another ajax 'GET' is used to call a 'code behind' function to to get the values for the controls in the new row (as can be seen in the above snippet).
Function that gets the item details of the Asset
public JsonResult OnGetPopulateLineItemRow(string _asset)
{
//stores named value pairs for the result
Dictionary<string, string> results = new Dictionary<string, string>();
//get record from the database for the specified asset (_asset)
var asset = from a in _context.Asset select a;
asset = asset.Where(a => a.Asset1 == _asset);
//get value for each field
var description1 = from d in asset select d.AssetDescription;
var description2 = from d in asset select d.AssetDescription2;
var inventoryNum = from d in asset select d.InventoryNo;
var serialNum = from s in asset select s.SerialNo;
//add the name value pairs to the collection
results.Add("description1", description1.ToList()[0].ToString());
results.Add("description2", description2.ToList()[0].ToString());
results.Add("inventoryNum", inventoryNum.ToList()[0].ToString());
results.Add("serialNum", serialNum.ToList()[0].ToString());
return new JsonResult(results);
}
Finally these results are passed back to the success function and JQuery is used to populate the values
function PopulateRow(asset, data,rowNum) {
$("#row" + "_" + rowNum).text($("#LineItems tr").length - 1);
$("#TransferLineItem_Asset" + "_" + rowNum).val(asset);
$("#TransferLineItem_AssetDescription1" + "_" + rowNum).val(data["description1"]);
$("#TransferLineItem_AssetDescription2" + "_" + rowNum).val(data["description2"]);
$("#TransferLineItem_InventoryNum" + "_" + rowNum).val(data["inventoryNum"]);
$("#TransferLineItem_SerialNumber" + "_" + rowNum).val(data["serialNum"]);
//reset drop down
$('#assetList').prop('selectedIndex', 0);
}
Just as a side note. Until recently I used ASP.net webforms. I'm still trying to understand how to accomplish what I considered to be simple things with server side coding that really, to me, seem to be more complicated with MVC and Razor.
I have a set of list elements, that I create dynamically. Each of these list elements, contains an input text, whose value I want to pass to the controller.
HTML
<ul id="list"></ul>
<button id="add">Add</button>
<script>
var counter = 1;
$('#add').click(function () {
var text = '<input type="text" name="(what should I put here?)"></input>';
var li = '<li>' + text + '</li>';
$(li).appendTo('#list');
counter++;
return false;
});
</script>
View Model
public IEnumerable<string> list {get; set;}
...
How can I bind those values to my ViewModel implicitly? I have tried to use the counter variable to assign a name to each created element (like list[counter]), but on the controller side the list variable on my ViewModel still comes empty.
First I would base your counter on the amount of li's within your un-ordered list with:
$('#list > li').size()
Then in order to keep the model binder happy pre-fix your property with list:
'<input type="text" name="list[' + counter + ']"></input>'
The full code then becomes:
$('#add').click(function () {
var counter = $('#list > li').size();
var text = '<input type="text" name="list[' + counter + ']"></input>';
var li = '<li>' + text + '</li>';
$(li).appendTo('#list');
return false;
});
jsFiddle
Please note, you will have to change your view model property to an IList or List for indexing to work too:
public IList <string> list {get; set;}
Because your collection is for value type (string) only, then you can simply use
$('#add').click(function () {
var text = '<input type="text" name="list"></input>';
....
});
It is only necessary to include indexers when the property is a member of a complex object.
If you do include the indexer, it must start at zero and be consecutive (unless you also include a special hidden input for to identify the indexer). Your attempt at using list[counter] failed because the value of counter is initialized to 1 (it would have worked had you initialized it to var counter = 0;)
I have a list of radiobuttons that I am generating from my model like this:
#foreach (var offer in Model.AvailableOffers)
{
<div>
#Html.RadioButtonFor(m => m.selectedAvailableOffer, offer)
#Html.Label(offer.begin_date.Month + "/" + offer.begin_date.Day + " - " + offer.end_date.Month + "/" + offer.end_date.Day + ", " + offer.offer_name)
</div>
}
Model includes these:
public List<AvailableOffer> AvailableOffers { get; set; }
public AvailableOffer selectedAvailableOffer { get; set; }
See how I am trying to post my offer object back to my controller in the RadioButtonFor method? This is obviously not working, but it's what I want to accomplish. Is there any way to post the whole selected offer object back to my controller or am I stuck adding some sort of ID to my object and only posting back the ID as is suggested here:
Correct way to bind an mvc3 radiobutton to a model
Shortly: No, you can't pass whole 'offer' object back to the server. It's better to use only id's on the client side.
If you realy want to post back whole offer you can use some kind of serialization to store data from each offer object as a value of radiobutton.
How can I set the Textbox's value equal to address bar?
for example :
localhost:28362/?f=Ava
when we click on a button the value of textbox must set to : Ava
?
Try this, Add Query String Jquery Js(querystring-0.9.0-min.js) in solution
$("#ButtonId").click(function(){
$("#textBoxID").val($.QueryString("f");)
});
Here is Javascript function to get query string value:
function getParameterByName(name) {
name = name.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]");
var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"),
results = regex.exec(location.search);
return results == null ? "" : decodeURIComponent(results[1].replace(/\+/g, " "));
}
Then you need to assign this value to a textbox. I would use jQuery:
$(function(){
$("#myTextBoxID").val(getParam("f"));
})
If you want a solution that uses MVC4 rather than JavaScript, define your controller method as:
public ActionResult Index(string f) {
return View(f);
}
In your view, you would then use one of:
#model string;
#Html.TextBoxFor(Model)
or
#model string
<input type='text' value='#Model' name='myValue' />
Obviously this is vastly oversimplified, but should give you a good starting point.
I'm passing a List to an MVC view and generating checkboxes for each object in the list (The checkboxes are named t.Name).
I'd like to be able to tell which checkboxes were checked once the form is posted. However, I'd like to avoid using the FormCollection object. Is there any way to do this?
Set the name of your checkboxes to something like "MyObject[" + index + "].Checked", and for each checkbox also put a hidden input field named something like "MyObject[" + index + "].Name" with the value set to t.Name.
If you name your fields like that, the default model binder can take your form values and map them to a list of objects with a Name property and a Checked property.
I would try something like the following:
<% foreach(var t in Model)
{ %>
<div>
<%= Html.Hidden("MyObject[" + index + "].Name", t.Name, new { id = "MyObject_" + index + "_Name" }) %>
<%= Html.Checkbox("MyObject[" + index + "].Checked", false, new { id = "MyObject_" + index + "_Checked" }) %>
</div><%
} %>
I use the anonymous type with id property so that the MVC framework components don't generate HTML elements with invalid id values, but it isn't really necessary.
Your action handling the post would look something like this:
[HttpPost]
ActionResult MyAction(IList<MyObject> objects)
{
foreach (MyObject obj in objects)
{
if (obj.Checked)
{
// ...
}
else
{
// ...
}
}
return View();
}