Send data from loop created input fields in view to mvc controller - c#

i have a view with different fields in a loop. Depending on the model it should create as much fields as counts for the loop. Here a example for the page:
_________ ___________ _________
|CONNECTOR| |SEARCHINPUT| |Selection|
|_________| |___________| |_________|
________________ ________________
|Add Search Field| |Sub Search Field|
|_B_U_T_T_O_N____| |_B_U_T_T_O_N____|
The View class looks like:
#model Modelle.Models.SearchModel
<table>
#for (int i = 0; i < (int)Model.SearchCount; i++)
{ <tr>
<th>#if (i > 0)
{<select name="ConnectorList" id="ConnectorList">
<option value="AND" #(Model.ConnectorList.ElementAt(i - 1).Equals("AND") ? "selected" : "")>AND</option>
<option value="OR" #(Model.ConnectorList.ElementAt(i - 1).Equals("OR") ? "selected" : "") >OR</option>
<option value="NAND" #(Model.ConnectorList.ElementAt(i - 1).Equals("NAND") ? "selected" : "") >NAND</option>
<option value="NOR" #(Model.ConnectorList.ElementAt(i - 1).Equals("NOR") ? "selected" : "") >NOR</option>
</select>}
</th>
<th>
<input name="SearchInput" id="SearchInput" type="text" value="#(Model.SearchList.ElementAt(i) as String)" /></th>
<th>
<select name="SelectionList" id="SelectionList">
#for (int j = 0; j < Model.SelectedList.Count(); j++)
{<option value="#j" #(Model.Selection.ElementAt(i).Equals(j) ? "selected" : "")>#(Model.SelectedList.ElementAt(j).Name as String)</option>
}
</select>
</th>
</tr>}
</table>
<p>
<button name="button" type="button" onclick="AddSearchField()">Add one more search field</button>
<button name="button" type="button" onclick="SubSearchField()">Remove one search field</button>
Here the jquery code for the buttons:
function AddSearchField() {
var value1 = $('#SearchInput').val();
var value2 = $('#SelectionList').val();
var value3 = $('#ConnectorList').val();
$.ajax({
url: "#Url.Action("AddSearchField", "Search")",
type: 'POST',
chache:false,
data: 'searchInput=' + value1 + '&selectionList=' + value2 + '&connectorList=' + value3,
success: function (response) {
$('#OpenSearchInput').html(response);
},
});
}
function SubSearchField() {
var value1 = $('#SearchInput').val();
var value2 = $('#SelectionList').val();
var value3 = $('#ConnectorList').val();
$.ajax({
url: "#Url.Action("SubSearchField", "Search")",
type: 'POST',
chache: false,
data: 'searchInput=' + value1 + '&selectionList=' + value2 + '&connectorList=' + value3,
success: function (response) {
$('#OpenSearchInput').html(response);
},
});
}
And the controller code:
public PartialViewResult AddSearchField(List<String> searchInput, List<int> selectionList, List<String> connectorList)
{
SearchModel searchModel = new SearchModel();
if (connectorList == null)
{
connectorList = new List<String>();
}
searchModel.ConnectorList = connectorList;
searchModel.Selection = selectionList.ToList();
searchModel.SelectedList = setSearchFields();
List<String> searchList = new List<String>();
int row = searchInput.Count();
searchModel.SearchList = searchInput.ToList();
searchModel.SearchList.Add("search");
searchModel.SearchCount = row + 1;
searchModel.ConnectorList.Add("AND");
searchModel.Selection.Add(0);
return PartialView("SearchInput", searchModel);
}
public PartialViewResult SubSearchField(List<String> searchInput, List<int> selectionList, List<String> connectorList)
{
SearchModel searchModel = new SearchModel();
if (connectorList == null)
{
connectorList = new List<String>();
}
searchModel.ConnectorList = connectorList;
searchModel.Selection = selectionList.ToList();
searchModel.SelectedList = setSearchFields();
List<String> searchList = new List<String>();
int row = searchInput.Count();
searchModel.SearchList = searchInput.ToList();
if (searchInput.Count() > 1)
{
searchModel.SearchList.RemoveAt(searchInput.Count() - 1);
searchModel.SearchCount = row - 1;
searchModel.ConnectorList.RemoveAt(connectorList.Count() - 1);
searchModel.Selection.RemoveAt(selectionList.Count() - 1);
}
else
{
searchModel.SearchCount = row;
}
return PartialView("SearchInput", searchModel);
}
If i load the page normally it has one search line. If i press the button "add one more search field" it added one line. If i click it a second time nothing happens. If i click the "Remove one search field button (anytime) the second fields disappear. In the debug mode, i can see that in the controller everytime the lists just count 1.
Did someone know where i´m mistaken?
Know anybody a easier way to add the lines? I have to send all the inputs later to the controler to search in a database with different rules depending on the inputs.

You are using
<input name="SearchInput" id="SearchInput" type="text" value="#(Model.SearchList.ElementAt(i) as String)" />
and all other form elements as well in a for loop.
therefore in DOM, you are rendering multiple fields with same ids('SearchInput','ConnectorList','SelectionList')
var value1 = $('#SearchInput').val(); assigns only one string value to value1,
data: 'searchInput=' + value1
here value1 will have only one stirng.
remove Ids for form elements
change your ajax call as
$.ajax({
url: "#Url.Action("SubSearchField", "Search")",
type: 'POST',
cache: false,
data: $('#the form tag id').serialize(),
success: function (response) {
$('#OpenSearchInput').html(response);
},
});

i got already a form around for the search request but i don´t mentioned i could use it for this problem to, cause it would need different buttons to call different methods. A litte workaround from Andrey Shchekin safed my day (http://blog.ashmind.com/2010/03/15/multiple-submit-buttons-with-asp-net-mvc-final-solution/ ) so i could use this form to solve my problem.
The view class now looks like:
#model Modelle.Models.SearchModel
<table>
#for (int i = 0; i < (int)Model.SearchCount; i++)
{ <tr>
<th>#if (i > 0)
{<select name="ConnectorList" id="ConnectorList">
<option value="AND" #(Model.ConnectorList.ElementAt(i - 1).Equals("AND") ? "selected" : "")>AND</option>
<option value="OR" #(Model.ConnectorList.ElementAt(i - 1).Equals("OR") ? "selected" : "") >OR</option>
<option value="NAND" #(Model.ConnectorList.ElementAt(i - 1).Equals("NAND") ? "selected" : "") >NAND</option>
<option value="NOR" #(Model.ConnectorList.ElementAt(i - 1).Equals("NOR") ? "selected" : "") >NOR</option>
</select>}
</th>
<th>
<input name="SearchInput" id="SearchInput" value="#(Model.SearchList.ElementAt(i) as String)" /></th>
<th>
<select name="SelectionList" id="SelectionList">
#for (int j = 0; j < Model.SelectedList.Count(); j++)
{<option value="#j" #(Model.Selection.ElementAt(i).Equals(j) ? "selected" : "")>#(Model.SelectedList.ElementAt(j).Name as String)</option>
}
</select>
</th>
</tr>}
</table>
<p>
<button name="AddSearchField" type="submit">Add one more search field</button>
<button name="SubSearchField" type="submit"">Remove one search field</button>
And the View with the form above:
#model Tumormodelle.Models.SearchModel
<h2>Search Request</h2>
<fieldset>
<legend id="SearchInputHeadline">Here you can Search for all accessible TumorModels</legend>
<b>#ViewBag.Message2 </b>
#using (Ajax.BeginForm("Action", "Search", null, new AjaxOptions { HttpMethod = "post"}, new { id = "SearchForm" }))
{
Html.RenderPartial("SearchFields");
Html.RenderPartial("SearchFilter");
<p>
<button name="SearchForTumorModels" class="submitSearchForm" value="OpenSearchOutput" type="submit">Search for tumor models</button>
<button name="button" type="submit">Clear the search form</button>
</p>}
</fieldset>
In this way i don´t need any jquery but a new class to handle the different buttons and redirect them to the right methods:
public class HttpParamActionAttribute : ActionNameSelectorAttribute
{
public override bool IsValidName(ControllerContext controllerContext, string actionName, MethodInfo methodInfo)
{
if (actionName.Equals(methodInfo.Name, StringComparison.InvariantCultureIgnoreCase))
return true;
if (!actionName.Equals("Action", StringComparison.InvariantCultureIgnoreCase))
return false;
var request = controllerContext.RequestContext.HttpContext.Request;
return request[methodInfo.Name] != null;
}
}
Last but not least i have to put [HttpParamAction] [AcceptVerbs(HttpVerbs.Post)] to the methods in the controller.
The main problem is solved now but it remains a little new problem. Depending on the button it should render the response in different div's.

Related

How to pass array using asp-route?

Form returns url format: localhost2343/index?Colors=red&Colors=blue&Colors=pink
asp-route return url format: localhost2343/index?Colors=red,blue,pink
If I use form submit button than everything seems good. But If i click on sort hyperlink than it will pass URL Colors=System.String%5B%5D
How can I pass value of Colors inside asp-route?
<form asp-page="./index" method="get">
<select asp-for="Colors" asp-items="#Model.Colors_SELECT" class="MultiSelect" multiple>
<option value="">All</option>
</select>
...
</form>
<Table>
...
<a asp-page="./Index" method="get"
asp-route-SortOrder="#Model.Colors_Sort"
asp-route-SearchString="#Model.SearchString"
asp-route-Colors="#Model.Colors">
#Html.DisplayNameFor(model =>
model.MyList[0].Colors)
</a>
...
</table>
[BindProperty(SupportsGet = true)]
public string[]? Colors { get; set; }
public SelectList? Colors_SELECT { get; set; }
public async Task OnGetAsync()
{
// Form - URL Format
// get values from URL & set inside selectlist
var result = Request.Query["Colors"];
var i = 0;
foreach (string? item in result) {
Colors[i] = item;
i++;
}
}
Update - I tried this but on sort link, it removes Sort variable & it picks only 1 Colors (not multi)
<a asp-page="./Index" method="get"
asp-route-SortOrder="#Model.Colors_Sort"
asp-all-route-data="#Model.routeData">
[BindProperty(SupportsGet = true)]
public Dictionary<string, string> routeData { get; set; }
....
var routeData = new Dictionary<string, string>();
routeData.Add("SortOrder", CurrentSort);
routeData.Add("SearchString", SearchString);
for (int i = 0; i < result.Count; i++)
{
var myParam = result[i];
routeData.Add($"Colors{i}", myParam.ToString());
}
This may help:
To get the selected values from a select element in a Razor page, you can use the Request.Form["selectName"] collection.
For example, consider the following select element:
#page "{Colors}"
<form method="post">
<select multiple name="colors">
<option value="red">Red</option>
<option value="blue">Blue</option>
<option value="pink">Pink</option>
</select>
<button type="submit" asp-page-handler="GetColors">Submit</button>
</form>
To get the selected values in the form submission handler and modify the query string in the URL and include the selected values (red, blue, pink), you can try the following code:
public IActionResult OnGet(string? Colors)
{
if (string.IsNullOrWhiteSpace(Colors))
{
// do something
return Page();
}
if (!string.IsNullOrWhiteSpace(Colors))
{
// Do something
return Page();
}
return Page();
}
public IActionResult OnPostGetColors()
{
IDictionary<string, string> params = new Dictionary<string, string>();
var selectedColors = string.Join(",", Request.Form["colors"]);
params.Add("Colors", selectedColors);
string query = "";
foreach (var p in params)
query += $"{p.Key}={p.Value}";
var url = $"{HttpContext.Request.Path}?{query}";
return Redirect(url); // url : https://localhost:7272/index?Colors=red,blue,pink
}
This code will help you submit the selected values through the URL as a query string, and then will redirect the user to a new URL with the selected values added to the query string as multiple values for the colors parameter.

Display incremented count from database table ID using Ajax

I want to get the last ID from a database table and increment by 1, to be displayed in an Input or Label parameter of HTML.
Most tutorials display it in tables. Here is my code:
index.cshtml
<td>Trans Id</td>
<td><input id="tbTransID" type="text" /></td>
<script>
$(document).ready(function () {
$.ajax({
type: "GET",
url: "/CashAdvance/GetTransID",
data: "{}",
success: function (data) {
var s = data.TransID;
}$("#tbTransId").html(s);
}
});
});
</script>
CashAdvanceController
public ActionResult GetTransID()
{
AcctgContext db = new AcctgContext();
return Json(db.CATransactions.Select(x => new
{
TransID= x.TransID + 1
}).ToList(), JsonRequestBehavior.AllowGet);
}
You need to change your linq query in the controller as below:
public ActionResult GetTransID()
{
AcctgContext db = new AcctgContext();
return Json(db.CATransactions.OrderByDescending(i => i.TransID).Select(i=>new
{
TransID= x.TransID + 1
}).FirstOrDefault(), JsonRequestBehavior.AllowGet);
}
In your query, you are selecting list of values whereas you need only the max id to increment it.

How can i create a SelectListItem() with Int Value

I have the folloiwng code inside my asp.net mvc action method:-
var CustomerData = customerlist.Select(m => new SelectListItem()
{
Text = m.SDOrganization.NAME,
Value = m.SDOrganization.ORG_ID.ToString(),
});
currently if i remove the ToString() from the ORG_ID , i will get an error that "can not explicitly convert long to string". so it seems that i have to define both the value and the text for the SelectListItem as strings. but since the SelectListItem should hold long , so is there a way to pass the values of the SelectListItem as long instead of strings?
...so is there a way to pass the values of the SelectListItem as long instead of strings?
No. And it doesn't make any sense to do so as when it is rendered, it's just HTML which has no concept of long.
If we have the action
public ActionResult Test()
{
var dictionary = new Dictionary<int, string>
{
{ 1, "One" },
{ 2, "Two" },
{ 3, "Three" }
};
ViewBag.SelectList = new SelectList(dictionary, "Key", "Value");
return this.View();
}
and the following view "Test.cshtml":
#using (Html.BeginForm())
{
#Html.DropDownList("id", ((SelectList)ViewBag.SelectList), "All")
<input type="submit" value="Go" />
}
The generated HTML is
<form action="/home/test" method="post">
<select id="id" name="id">
<option value="">All</option>
<option value="1">One</option>
<option value="2">Two</option>
<option value="3">Three</option>
</select>
<input type="submit" value="Go">
</form>
and when we post to this action, text of your number is effectively parsed back into your desired type by the Model Binder
[HttpPost]
public ActionResult Test(int? id)
{
var selectedValue = id.HasValue ? id.ToString() : "All";
return Content(String.Format("You selected '{0}'", selectedValue));
}
And the above works as you might expect.

Why my drop down list items are invisible?

I am trying to make 2 cascading drop down lists.
First one works fine, you pick an item but when you go to the second drop down list, you can actually see correct number of spaces generating according to the items in the database but not the items themselves!
Its like they are invisible!
Can you please advise?
My View :
#using (Html.BeginForm("Browse", "Bookings", new { id = "TypeItemFormID", data_itemsListAction = #Url.Action("ItemsList") }))
{
<fieldset>
<legend> Type/Item</legend>
#Html.DropDownList("department", ViewBag.ItemTypesList as SelectList, "Select a Type", new {id="ItemTypeID"})
<div id="ItemsDivId">
<label for="Items">Items </label>
<select id="ItemsID" name="Items"></select>
</div>
<p>
<input type ="submit" value="Submit" id="SubmitID" />
</p>
</fieldset>
}
<script type="text/javascript">
$('#ItemTypeID').on('change', function () {
$.ajax({
type: 'POST',
url: '#Url.Action("GetItemTypeForm")',
data: { itemTypeId: $('#ItemTypeID').val() },
success: function (results) {
var options = $('#ItemsID');
options.empty();
options.append($('<option />').val(null).text("- Select an Item -"));
$.each(results, function () {
options.append($('<option />').val(this.ItemsID).text(this.Value));
});
}
});
});
</script>
My Controller :
[HttpPost]
public JsonResult GetItemTypeForm(string itemTypeId)
{
//pseudo code
var data = from s in db.Items
where s.ItemType.ItemTypeName == itemTypeId
select s.ItemName;
return Json(data);
}
You have the initial problem I mentioned in my comment, but it appears from your comments that your member names probably do not match either.
This may not be exact, as we do not know all your data/member names, but you may want something like this (using an anonymous type to return the shape of data you expect):
[HttpPost]
public JsonResult GetItemTypeForm(string itemTypeId)
{
//pseudo code
var data = from s in db.Items
where s.ItemType.ItemTypeName == itemTypeId
select new { Value = s.ItemName, ItemsID = s.ItemId };
return Json(data);
}

Check for empty value in C# - Webmatrix

I am populating an input field value where sometimes the value exists and sometimes it doesn't I need to check if the value is empty and show nothing if it is not. My current code is using .IsNullOrEmpty :
<input id="lead-entry" class="form-textbox" type="text" size="5" name="q15_2013Collections[0][]"
value="#(queryinputvalue.FirstOrDefault(r => r.field_name.Equals("q15_2013Collections[0][]")).field_data.IsNullOrEmpty
? ""
: queryinputvalue.FirstOrDefault(r => r.field_name.Equals("q15_2013Collections[0][]")).field_data) " />
Which gives me the error:
Exception Details: Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: Cannot perform runtime binding on a null reference
Thanks
Edit: this is the code I finally used:
Helpers.cshtml
#helper checkEmpty(IEnumerable<dynamic> queryinputvalue, string field_id) {
var reqValue = queryinputvalue.FirstOrDefault(r => r.field_name.Equals(field_id));
var return_value = "";
if(reqValue != null){
return_value = reqValue.field_data;
} else {
return_value = "";
}
#return_value
}
On Page
#{
IEnumerable<dynamic> queryinputvalue = db.Query("SELECT * FROM document_data WHERE doc_id = #0", doc_id);
}
<input type="text" class=" form-textbox" id="input_4" name="q4_arborLoan" size="20" value="#Helpers.checkEmpty(queryinputvalue,"q4_arborLoan")" />
Why are you doing this in View? You have to check for these conditions in the controller while populating your ViewModelas below:
public class ViewModel
{
public string QueryValue {get ; set;}
}
And in your controller method you would simply populate this model and return it in View page.
public ActionResult MyMethod()
{
ViewModel model = new ViewModel();
//Get someValue from anywhere.
string reqValue = someValue.FirstOrDefault(r => r.field_name.Equals("q15_2013Collections[0][]"));
string queryValue = string.Empty();
if(queryValues != null)
{
queryValue = string.IsNullOrEmpty(reqValue .field_data)
? ""
: reqValue .field_data;
}
model.QueryValue = queryValue ;
return View(model);
}
So, your View will simply become
#model ViewModel
<input id="lead-entry" class="form-textbox" type="text" size="5" name="q15_2013Collections[0][]" value="#Model.QueryValue" />

Categories