.NET use partial view multiple times - c#

my UI has a text box and a button, everytime I add a new element I need to show the list in the same view. I'm using partial view so I need to keep loading this partial view everytime I add a new element to my list. how can I modify my code to achieve that?
View
#Html.TextBoxFor(m => m.emailsAdded, new { #class = "form-control wide", placeholder = "Email ID", type = "email", Name = "txtEmail" }
<button id="thisButton">Add</button>
<div id="content"></div>
<script>
$(document).ready(function() {
$("#thisButton").on("click", function () {
var val = $('#emailsAdded').val();
$.ajax({
url: "/Admin/UpdateEmailList?email="+val,
type: "GET"
})
.done(function(partialViewResult) {
$("#content").html(partialViewResult);
});
});
});
</script>
Model
public class ABC
{
public IEnumerable<string> emailsAdded { get; set; }
}
Controller
[HttpGet]
public ActionResult UpdateEmailList(string email)
{
if (Session["emails"] == null)
{
List<string> aux1 = new List<string>();
aux1.Add(email);
Session["emails"] = aux1;
}
else
{
List<string> aux2 = new List<string>();
aux2 = (List<string>)Session["emails"];
aux2.Add(email);
Session["emails"] = aux2;
}
var abc = new ABC
{
emailsAdded = (List<string>)Session["emails"]
};
return PartialView("_EmailsListPartialView", abc);
}
Partial view
#using project.Models
#model project.Models.ABC
<table class="tblEmails">
#foreach (var emails in Model.emailsAdded)
{
<tr><td>#emails.ToString()</td></tr>
}
</table>
With my code I'm able to reload my div and add the new element, when doesn't work for the second time....how can I modify my code so I can keep adding stuff?
SOLUTION:
I updated my controller to show how I resolved this issue. Not really sure if it is the best way to do it, but at least helped me to resolve.
I'm storing the list of emails in Session["emails"] and every time I add a new email to the list, I just update it a pass it to a new list with all the records and at the end return the partial view.

Related

How to pass the ID of an object from a form to an action in ASP.NET MVC

I have an ASP.NET MVC project with entities based on EF6 (model first). So my entities are all auto-generated for me. I have an entity, Site and I just want the user to select a Site before proceeding. I have tried a couple of ways, all of them work, but they seem very messy and unnecessary.
I was curious about the cleanest way to create a DropdownList of Sites, then get the selected site when the form is submitted (by Id or whatever other mechanism is better).
Currently I have:
The index where the user is asked to select a site:
public ActionResult Index()
{
ViewBag.Sites = new SelectList(db.Sites.ToList(), "Id", "Name");
return View();
}
The view:
#using (Html.BeginForm("SetSite", "Home"))
{
#Html.Label("sites", "Site:");
#Html.DropDownList("Sites", null, new { #class = "selectpicker" });
<div style="width:100%;height:25px"></div>
<button class="btn btn-default" style="width:100%">Go</button>
}
And the SetSite action, where the form is submitted
[HttpPost]
public ActionResult SetSite()
{
if (Request.Form["Sites"] != null)
{
Session["Site"] = db.Sites.Find(Request.Form["Sites"]);
return RedirectToAction("Home");
}
else
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
}
A few problems arise from this method. First, I really wanted to take advantage of the #model functionality in razor and point it towards my Site class, but since it's auto-generated, I don't want to go poking around and adding a whole bunch of view properties. (beggars can't be choosers?)
Second, the Request.Form['Sites'] returns a string, and converting it to and int is ugly as hell.
As I mentioned, I'd like to use the #model functionality with Html.DropDownListFor. Is that possible when working with a list of Sites from the DB?
How can I get this done cleanly?
Solution 1:-
Controller:-
private List<Country> GetCountries()
{
var list = new Entity.Result<List<Entity.Country>>();
list = _context.Countries.Select(tc => new Entity.Country
{
Id = tc.Id,
Name = tc.Name,
IsdCode = tc.Code,
}).ToList();
return list.Data.Select(x => new Country
{
id = x.Id,
Name = x.Name,
}).ToList();
}
HttpGet Method:-
public ActionResult Add(int id)
{
try
{
}
catch (Exception ex)
{
}
finally
{
ViewBag.countryList = GetCountries();
}
return View()
}
View Method:-
#Html.DropDownListFor(x => x.countryId, new SelectList(ViewBag.countryList, "id", "Name"), KahandasDhanji.Common.Localization.Application.Resources.ddlCountry,
new { #id = "ddlCountry", #rows = 1 })
In Http Post Form Submitimg u handle that model value in HTTPPOST Method.
Solution 2:-
FormCollection class we can capture the form's values within the controller.
[HttpPost]
public ActionResult Add(FormCollection form)
{
string strDDLValue = form["Sites"].ToString();
return View(MV);
}
Hope Its Work !!!
You can use a ViewModel to avoid converting the string value from Request.Form. Below is how your ViewModel class should look like
public class MyViewModel
{
public MyViewModel()
{
this.DropdownItems = new List<SelectListItem>();
}
public int SelectedSiteId { get; set; }
public List<SelectListItem> DropdownItems { get; set; }
}
Change the get action method in your controller as below
public ActionResult Index()
{
List<Site> sites = db.Sites.ToList();
MyViewModel model = new MyViewModel();
foreach(var site in sites)
{
model.DropdownItems.Add(new SelectListItem() { Text = site.Name, Value = site.ID.ToString() });
}
return View(model);
}
Add #model MyViewModel at the first line in your view code and use Html.DropDownListFor method to generate the dropdownlist
#model MyViewModel
#using (Html.BeginForm("SetSite", "Home"))
{
#Html.Label("SelectedSiteId", "Site:");
#Html.DropDownListFor(m => m.SelectedSiteId, Model.DropdownItems, new { #class = "selectpicker" })
<div style="width:100%;height:25px"></div>
<button class="btn btn-default" style="width:100%">Go</button>
}
The post action method in your controller should look like below. model.SelectedSiteId will be the selected value of the dropdownlist and the type is int so you won't have to do any conversion such as Convert.ToInt32(Request.Form['Sites']).
[HttpPost]
public ActionResult SetSite(MyViewModel model)
{
Session["Site"] = model.SelectedSiteId;
return RedirectToAction("Home");
}

Change value of EditorFor on DropDownFor value change

I am trying to make an online bank website(for learning ASP.NET MVC).I have a class Account
class Account
{
int account_id;
String account_number;
decimal balance;
}
and I have a model for transaction.
public class MakeTransactionModel
{
[Required]
public String AccountFrom { get; set; }
[Required]
public String AccountTo { get; set; }
public Decimal OrignalBalance { get; set; }
[Required]
public Decimal Amount { get; set; }
[Required]
public String TransactionFor { get; set; }
}
Then in controller, i am putting accounts in ViewBag.
ViewBag.account_from = new SelectList(db.Accounts, "account_id", "account_number");
In View, I created a drop down for showing all accounts
#Html.DropDownListFor(u => u.AccountFrom, (SelectList)ViewBag.account_from, htmlAttributes: new { #class = "form-control", #id = "AccountFrom", onchange=#"
#Model.OrignalBalance = 1000; // I tried this but did not work
" })
Now , I am trying to show balance of selected account in an EditorFor
#Html.EditorFor(model => model.OrignalBalance, new { htmlAttributes = new { #id="OrignalBalance", #class = "form-control", disabled = "disabled", #readonly = "readonly" } })
I have all accountsin ViewBag and I am showing that accounts number in drop down (those accounts also have balance in it). I am trying to change value of EditorFor on DropDownFor value change but still unable to do that. I tried to do that using jquery, but i don't know can I use LINQ in jquery
My jquery code is
<script type="text/javascript">
$(document).ready(function () {
$(function () {
$('#AccountFrom').change(function () {
var selectedValue = $('#AccountFrom').text();
$('#OrignalBalance').val(#{new BankEntities().Accounts.SingleOrDefault(acc => acc.account_number == $('#AccountFrom').text())}); // I am trying to do this
});
});
}
)
</script>
It will be good if i find a good solution to do that, so I can update EditorFor on change event.
Thank you.
You should make an ajax call and pass the account number and get the amount from the server.
$(function()
{
$('#AccountFrom').change(function() {
var accountId= $('#AccountFrom').val();
var url="#Url.Action("Balance","Account")";
$.post(url+"?accountNumber="+accountId,function(response){
if(response.Status==="success")
{
$("#OrignalBalance").val(response.Balance);
}
else
{
alert("Invalid Account");
}
});
});
});
Assuming you have an action method to return the balance
[HttpPost]
public ActionResult Balance(string accountNumber)
{
//Of course you want to authorize the call
var db=new BankEntities();
var a= db.Accounts.FirstOrDefault(x=> x.account_number ==accountNumber);
if(a!=null)
{
return Json( new { Status="success", Balance=a.Balance });
}
else
{
return Json( new { Status="error"});
}
}
If you do not wish to make an action method and the ajax way, What you can do is, Create a dictionary of your account number and the balance and pass that as part of your view model and in your razor view, set that to a js object and in the change event you can query the js dictionary to get the value.
Also, I recommend to NOT use ViewBag to transfer data between your action method and your view for rendering the dropdown. You should add a strongly typed property to handle that.
So let's add some new properties to your view model.
public class MakeTransactionModel
{
// Your other existing properties here
public Dictionary<string,decimal> AccountBalances { set; get; }
// These 2 properties are for rendering the dropdown.
public int FromAccountId { set; get; }
public List<SelectListItem> FromAccounts { set; get; }
}
And in your GET action, fill this property with account number and corresponding balance value.
public ActionResult Transfer()
{
var vm = new MakeTransactionModel();
vm.AccountBalances = new Dictionary<string, decimal>();
// Hard coded for demo. You may read it from your db tables.
vm.AccountBalances.Add("CHECKING0001", 3450.50M);
vm.AccountBalances.Add("SAVINGS0001", 4450.50M);
//load the data for accounts.pls change to get from db
vm.FromAccounts = new List<SelectListItem>
{
new SelectListItem { Value="CHECKING0001", Text="Checking" },
new SelectListItem { Value="SAVINGS0001", Text="Saving" }
};
// to do : Load other properties also
return View(vm);
}
And in your razor view, serialize this property and set to a js object.
#model MakeTransactionModel
#using(Html.BeginForm())
{
#Html.DropDownListFor(s=>s.FromAccountId,Model.FromAccounts,"Select")
#Html.EditorFor(model => model.OrignalBalance,
new { #id="OrignalBalance", #class = "form-control",
disabled = "disabled", #readonly = "readonly" } )
<input type="submit" />
}
#section Scripts
{
<script>
var balanceDict = #Html.Raw(Newtonsoft.Json.JsonConvert
.SerializeObject(Model.AccountBalances));
$(function () {
$('#FromAccountId').change(function() {
var accountId= $('#AccountFrom').val();
var v = balanceDict[accountId];
$("#OrignalBalance").val(v);
});
});
</script>
}
It may not seem like it, but this is pretty broad. Basic rundown, you'll either have to:
Serialize all accounts and balances into JSON and store them client-side:
This is more code than is appropriate here, but you could use JSON.net to get JSON for new BankEntities().Accounts.ToList() (something you should be getting from your controller code, by the way, not in your view), then set a window variable to that in your JavaScript, and call upon that whenever the value changes.
Untested, but something like:
var balances = #Html.Raw(JsonConvert.SerializeObject(new BankEntities()
.Accounts
// Filter by logged in user
.ToDictionary(c => c.account_number, c.balance));
$(document).ready(function () {
$(function () {
$('#AccountFrom').change(function () {
var selectedValue = $('#AccountFrom').text();
$('#OrignalBalance').val(balances[selectedValue]);
});
});
}
Introduce an API call performed through AJAX to get balances whenever the value changes.
Shyju beat me to this one, but it's probably a better way to do it, as long as you're comfortable introducing an API element. It's kind of advanced for first learning MVC, but it's not too complicated.
This is what I'd do in a production application (although I'd do it with Web API), but for just playing, the first option is a little quicker, and probably easier to understand and debug fully if you're just getting started.
The confusion here comes from where code is executed. Your script can't refer to the BankEntities because it's running client-side, as compared to server side.
JQuery knows nothing about LINQ, since it is client based. So, I suggest making an ajax request when the account from gets changed.
for example, in the view, make the ajax call
<script type="text/javascript">
$(document).ready(function() {
$('#AccountFrom').change(function() {
var selectedAccountNumber = $('#AccountFrom option:selected').text();
$.ajax({
url: "/Accounts/GetAccountBalance",
type: "POST",
dataType: "json",
data: { accountNumber: selectedAccountNumber },
success: function (
$('#OrignalBalance').val(data.Balance);
}
});
});
});
</script>
and have the following in the controller (let's say that you have a controller called Accounts)
public ActionResult GetAccountBalance(string accountNumber)
{
var account = db.Accounts.SingleOrDefault(a => a.account_number == accountNumber);
// add validation logic for account not exits
return Json(new { AccountNumber = accountNumber, Balance = account.balance });
}

How to call multiple actions in View in ASP.NET MVC?

Problem is:
I am using a textbox to get a string q and want to pass it to 3 different actions in search controller. i.e. action1(string q), action2(string q) and so on
Now syntax of my action:
public ActionResult action1(string q)
{
var mydata = from p in fab //LINQ logic
select new action1class
{ data1=p //assignment };
return View("_partialAction1", mydata);
}
Similarly there are two other actions.
I am using 3 different actions because my LINQ logic gets data from 3 different sources so there different mydata needs to be created.
My problem is: I am trying that when I click on 'search' Button of textbox then all the 3 actions should run and generate partial view one below other in some <div id="action1"> tags.
I tried to use ajax.BeginForm but it can only call one action at a time
#using (Ajax.BeginForm("action1", "Search", new AjaxOptions
{
HttpMethod = "GET",
InsertionMode = InsertionMode.Replace,
UpdateTargetId = "action1",
LoadingElementId="progress"
}))
Also I tried to use ViewModel but the problem is that I was unable to pass a bigger model to the view along with these mydata kind of data obtained in LINQ's in the action. I have no clear idea of how to use viewmodel in this case.
Is the approach that I am using correct? Or can there be any other way? I want to show result of all actions with button click.
There are two types of actions are in MVC framework. The first ones are the main actions and they are invoked from the browser one at a time. The second type are called as Child Actions and these actions can't be invoked from the browser but from the views returned by the main actions. Multiple child actions can be called under a main action. So you have to look into child actions whether they help or not.
Ex.
// main action that returns a view
public ViewResult Index()
{
var model = ...
return View(model);
}
// couple of child actions each returns a partial view
// which will be called from the index view
[ChildActionOnly]
public PartialViewResult ChildAction1()
{
var model = ...
return PartialView(model);
}
[ChildActionOnly]
public PartialViewResult ChildAction2()
{
var model = ...
return PartialView(model);
}
// index view
Index.cshtml
#model ...
#Html.Action("ChildAction1");
#Html.Action("ChildAction2");
...
http://msdn.microsoft.com/en-us/library/ee839451.aspx
You can only have one action per request. If you want to have 3 different partial views for a singular click, you will need to construct a layout page that includes the 3 partial views how you want them and make sure that your action receives the proper parameters to perform all of the partial view rendering.
Why not pass the ViewModel to the partialViews. Make sure you have different properties in the ViewModel to hold the PartialView Specific data plus the search text. Here is an example:
Model
public class Product
{
public string Name { get; set; }
public string Type { get; set; }
public string Class { get; set; }
}
ViewModel
public class ProductSearch
{
public ProductSearch()
{
q = string.Empty;
Product1 = new Product();
Product2 = new Product();
}
public string q { get; set; }
public Product Product1 { get; set; }
public Product Product2 { get; set; }
}
_Partial1.cshtml
#model Test1.Models.ProductSearch
<div>Product1</div>
#Html.TextBoxFor(a => a.Product1.Name)
_Partial2.cshtml
#model Test1.Models.ProductSearch
<div>Product2</div>
#Html.TextBoxFor(a => a.Product2.Name)
ActualView.cshtml
#model Test1.Models.ProductSearch
#{
ViewBag.Title = "ActualView";
}
<h2>ActualView</h2>
#using (Html.BeginForm())
{
#:SearchText
#Html.TextBoxFor(m => m.q)
Html.RenderAction("_Partial1", Model);
Html.RenderAction("_Partial2", Model);
<input type="submit" runat="server" id="btnSubmit" />
}
Temp Data (you will be getting it from DB/ any other source)
private List<Product> ProductsToSearch()
{
return new List<Product>() { new Product() { Name = "Product One", Class = "A", Type = "High" }, new Product() { Name = "Product Two", Class = "A", Type = "Low" }, new Product() { Name = "Product Three", Class = "B", Type = "High" } };
}
Controller Actions
public ActionResult _Partial1(ProductSearch search)
{
Product Product1 = ProductsToSearch().Where(a => a.Class.Equals(search.q) && a.Type.Equals("High")).SingleOrDefault();
search.Product1 = Product1;
return PartialView(search);
}
public ActionResult _Partial2(ProductSearch search)
{
Product Product2 = ProductsToSearch().Where(a => a.Class.Equals(search.q) && a.Type.Equals("Low")).SingleOrDefault();
search.Product2 = Product2;
return PartialView(search);
}
[HttpPost]
public ActionResult ActualView(ProductSearch search)
{
return View(search);
}
public ActionResult ActualView()
{
ProductSearch search = new ProductSearch();
return View(search);
}
Now if you enter 'A' for SearchText and hit Submit Query you will get two different results (basically common search text is used and based on the search query in each partial view it has generated different results)

Mvc3 and Jquery Multiselect, sending values to server not working?

I am trying to use Jquery Multiselect plugin from Beautiful site and MVC3 together to send values to server. As shown in example from Darin the key is to create MultiSelectModelBinder class that will, I guess, recognize values send from client, because the multiselect plugin uses the [] notation to send the selected values to the server. My aproach is a little diferent, i fill dropDownList from my controller and not the model, keeping the model clean, and also been able to fill the list from Database. I used Darins example to create MultiSelectModelBinder and register it,in the model binder in Application_Start(). My problem is that I always keep getting empty Model back to my controller, here is the code:
MODEL:
public class PersonsSearchModel
{
public string Person { get; set; }
public string Company { get; set; }
//here is my Cities collection
public IEnumerable<string> Cities { get; set; }
}
VIEW:
#model MyNamespace.Model.PersonsSearchModel
#using (Ajax.BeginForm("Search", "Persons", new AjaxOptions
{
HttpMethod = "GET",
InsertionMode = InsertionMode.Replace,
UpdateTargetId = "results",
LoadingElementId = "progress"
},
new { #id = "searchFormPerson" }
))
{
<span>
#Html.TextBoxFor(x => Model.Person, new { #class = "halfWidth"})
</span>
<span>
#Html.TextBoxFor(x => Model.Company, new { #class = "halfWidth"})
</span>
<span>
#Html.ListBoxFor(x => x.Cities, Model.Items, new { #id="combobox1"})
</span>
<input name="Search" type="submit" class="searchSubmit" value="submit" />
}
CONTROLLER:
public ActionResult Index()
{
var listCities = new List<SelectListItem>();
listCities.Add(new SelectListItem() { Text = "Select one...", Value = "" });
listCities.Add(new SelectListItem() { Text = "New York", Value = "New York" });
listCities.Add(new SelectListItem() { Text = "Boston", Value = "Boston" });
listCities.Add(new SelectListItem() { Text = "Miami", Value = "Miami" });
listCities.Add(new SelectListItem() { Text = "London", Value = "London" });
ViewBag.Cities = listCities;
return View();
}
public class MultiSelectModelBinder : DefaultModelBinder
{
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
var model = (PersonsSearchModel)base.BindModel(controllerContext, bindingContext);
var value = bindingContext.ValueProvider.GetValue(bindingContext.ModelName + "[]");
if (value != null)
{
return value.RawValue;
}
return model;
}
}
Here the data from client sholud arive, butt is always null?
public PartialViewResult Search(PersonsSearchModel psm)
{
var person = psm.Person;
var company = psm.Company;
var city = psm.Cities.ElementAt(0);
return GetResultPartialView(city);
}
GLOBAL.asax.cs
protected void Application_Start()
{
//...
//model binder
ModelBinders.Binders.Add(typeof(IEnumerable<string>), new
FinessenceWeb.Controllers.PersonsController.MultiSelectModelBinder());
}
JQUERY
$("#combobox1").multiSelect();
I had the same issue, although your provided solution still works. There is another way of doing it with less effort.
Actually defaultModelbinder does bind to multiple selected values if you can change your input parameter to List<inputparameter> and change the line #Html.DropDownListFor to #Html.ListBoxFor.
The key difference between these 2 controls is, First one being a single selection box and second one being a multiple selector.
Hope this helps some one having the same issue.
Well... After looking into DOM, and Jquery plugin, turns out the plugin gives the select element, atribute name, current id, so they are the same, and the form, well.. look's at the name attr. So solution wolud be:
$("#Cities").multiSelect();
Cheers!

Returning the View Model to a Controller from a Form.Submit client action

I have a controller with 2 Index methods:
public ActionResult Index()
{
viewModel.PipelineIndex pivm = new viewModel.PipelineIndex(null, User.Identity.Name);
return View(pivm);
}
[HttpPost]
public ActionResult Index(viewModel.PipelineIndex model, FormCollection collection)
{
viewModel.PipelineIndex pivm = null;
if (ModelState.IsValid)
{
string key = collection.AllKeys[0];
string ID = collection.Get(key).ToString();
pivm = new viewModel.PipelineIndex(ID, User.Identity.Name);
}
else
pivm = new viewModel.PipelineIndex(null, User.Identity.Name);
return View(pivm);
}
The ViewModel I am using is a well defined class:
public class PipelineIndex
{
private Models.Context _db = new Models.Context();
public List<SelectListItem> GroupList { get; set; }
public List<string> ButtonCaptions { get; set; }
public List<ContactDetail> ContactList { get; set; }
public string PageTitle { get; set; }
...
The View consumes the ViewModel setting up a Grid and a Drop Down control:
#model BlueSkies.Pipeline.ViewModels.PipelineIndex
#{ ViewBag.Title = "Index"; }
#using (Html.BeginForm())
{
<h2>#Model.PageTitle</h2>
<div style="clear:both">
#if (Model != null)
{
var grid = new WebGrid(canPage: true, rowsPerPage: 15, canSort: true, ajaxUpdateContainerId: "grid");
grid.Bind(Model.ContactList, rowCount: Model.ContactList.Count, autoSortAndPage: true);
grid.Pager(WebGridPagerModes.All);
#grid.GetHtml(htmlAttributes: new { id = "grid" },
columns: grid.Columns(
grid.Column(format: (item) => Html.ActionLink("View", "Details", "Contacts", new { ID = item.Name }, null)),
grid.Column(format: (item) => Html.ActionLink("Edit", "Edit", "Contacts", new { ID = item.Name }, null)),
grid.Column("Name"),
grid.Column(columnName: "Phone1", header: "Phone")
));
}
</div>
<hr />
<div>
#*foreach (string caption in ViewBag.ButtonCaptions)
{
#Html.ActionLink(caption, "Index", "Pipeline", new { ID = caption }, new { #class = "menuSubButton" })
}*#
#Html.DropDownList("GroupDropDown", Model.GroupList, new { #onchange = "this.form.submit()" }) Select a pipe section...
</div>
}
Where I am having challenges is when the Drop Down fires the Form.Submit (on the onChange event). No model is being returned to my Controller. I do have the FormCollection but I would rather have the updated model including the new selectedItem in the drop down. What am I missing? And yes, I am looking for a non-JS based solution at this point - or as close as I can. I don't want to AJAX this page.
TIA
NOTE: There is a similar question here. It is AJAX based but getting the same null model on call into the controller. Why is it so hard to find the right answer? :)
I think the rendered HTML form will have a select with the name "GroupDropDown", is that right? If so, the selected value will be posted back on submit with that name and would be bound to either a parameter called groupDropDown or to a string property GroupDropDown on your model class. Do you have such a property on your model?
I am mentally exhausted, so I add this disclaimer. Thought Answering a question would get me away from my day.
The business problem appears to be "select one item from drop down and have contents rendered accordingly". If that is correct, there is no need to pass back the entire contents of the View Model; you only need to pass back the id, which is demoed numerous times on many sites.
Am I missing something?

Categories

Resources