ASP.NET MVC remove dynamically created views - c#

I have a view model in my ASP.NET MVC app that holds a List of objects. Each of these objects are visualized using EditorTemplate. Using a dropdown I can add dynamically new object to the List on postback. The problem is when I try to remove a specific element from the list.
public class MyViewModel
{
public List<MyModel> Items { get; set; }
public MyViewModel()
{
this.Items = new List<MyModel>();
}
}
public class MyModel
{
public int Id { get; set; }
public string Text { get; set; } // I bind this to UI using EditorFor html helper
}
HomeController:
[HttpPost]
public ActionResult Index(MyViewModel myViewModel)
{
myViewModels.Items.Add(new MyModel()); // Simulate initializing the Id and Text properties
return View(myViewModel);
}
Then in Index.cshtml:
if (Model.Items != null)
{
#Html.EditorFor(m => Model.Items); // EditorTemplate is used here...
}
So in my template file, called Item.cshtml I have:
#model MVCApp.Models.MyModel
<div>
#Html.HiddenFor(m => m.Id)
#Html.EditorFor(m => m.Text)
<span class="deleteItem" data-item-id="#Model.Id">Delete</span>
</div>
Now I don't know how to process the deletion of the specific item when I click on "Delete". My goal is to have the item deleted from the collection in the controller ('Items' list property of the view model). I can delete the div element using jQuery but the property would not be removed from the 'Items' collection and I would like to avoid jQuery to preserve data integrity between server and client side. I tried to call another action in HomeController called Remove(int? id) where the id parameter is the Id property of 'MyModel', but I need to pass 'MyViewModel' object in Remove action in order to access the 'Items' list, remove the element and then redirect to 'Index' action with the changed collection. How can I achieve that? Thanks!
Update

If you are looking to do it using. You can submit form using submit button and pass in the id to remove and then calling controller action and code accordingly.

Related

Add model into model using Html helper HiddenFor C# MVC

I have a model like
public class Model
{
public int Value { get; set; }
public List<OtherModel> List { get; set; }
}
public class OtherModel
{
public int Value1 { get; set; }
public int Value2 { get; set; }
public bool IsPropTrue { get; set; }
}
I am using Model in a View where I'm looping through the List to show data in a table.
Depending on whether one of the properties (IsPropTrue) in OtherModel is true or false, I want to use the HiddenFor Html helper and send the data to the HttpPost controller.
#model Model
#foreach (var item in Model.List)
{
if (item.IsPropTrue)
{
#Html.HiddenFor(model=> item.Value1)
#Html.HiddenFor(model=> item.Value2)
}
}
I think it doesn't work because I should in some way add these properties to the OtherModel, which is inside the Model; But the way I have it now, I am adding properties to Model.
you can do it like this :
#model Model
#foreach (var item in Model.List)
{
if (item.IsPropTrue)
{
#Html.HiddenFor(model => model.List[Model.List.IndexOf(item)].Value1)
#Html.HiddenFor(model => model.List[Model.List.IndexOf(item)].Value2)
}
}
this way the binding system will bind the hidden fields with your List OtherModel in the Model
if you want send an array to server based on the Model you have to use indexer in #Html.HiddenFor .
#model WebApplication1.Models.MyModel
<form>
#if (Model != null && Model.List != null)
{
for (int i = 0; i < Model.List.Count; i++)
{
if (Model.List[i].IsPropTrue)
{
#Html.HiddenFor(model => Model.List[i].Value1)
#Html.HiddenFor(model => Model.List[i].Value2)
}
}
}
<button type="submit">submit</button>
</form>
if you want know reason of using indexer on model i recommend How does MVC 4 List Model Binding work?
Consider if it the responsibility of the view or the controller action to make the decisions - you can send everything back to the action to do the decision making.
In your Views/Shared folder, create a controller called EditorTemplates
In this folder, add a partial view called OtherModel
In this view, set the model to OtherModel and set the Layout=null
Add the three OtherModel fields in EditorFor (and HiddenFor if not displaying isPropTrue). This partial view displays just one instance of your list.
In your main view, use the above editor model like so. MVC will take care of all rendering and postback of the Model State for your complete list of items. We like one-liners...
#Html.EditorFor(model => model.OtherModel)
When the data is subsequently posted back to an action, Model State has wrapped up all of your displayed items into a list again, so you can check the isPropTrue value for each item on the server.
The only issue with MVC is that is you pass an empty list out to a view, you get a null value back, so just replace this with an empty list when null is returned

Data Binding in ASP.NET MVC

I know it would be a basic question but I'm a newbie to ASP.Net MVC. I have fetched data from database using LINQ but there is an issue. I wanna bind that data with input fields of a customized webform. (I'm using MVC). I wanna populate the input fields of webform with fetched data. I'm using EF Database first approach.
My Controller and view is attached.
Controller ActionMethod
public class HomeController : Controller
{
public ActionResult Index()
{
AutoRTGSEntities_1 dc = new AutoRTGSEntities_1();
//dc.policies.Where(cb => cb.Section_Key.Contains("SenderBIC"));
return View(dc.policies.Where(cb => cb.Policy_Section.Contains("RTGS")).ToList()); //get RTGS policy section data
}
}
View
#model IEnumerable<Swift_MT_103.policy>
#{
ViewBag.Title = "Home Page";
}
<div> #Model{ #Html.TextBoxFor(x => x.data_Value)) } </div>
<div> <input type="text" name="ReceiverBIC" id="ReceiverBIC" /> </div>
Rest is HTML and CSS. Snap is attached.
Here's a very basic example of how to this. Let's say you have following class:
public class User
{
public int Id { get; set; }
[Display(Name = "Name")]
public string Name { get; set; }
[Display(Name = "E-mailaddress")]
public string E-mail { get; set; }
}
In the controller you get the user:
public ActionResult Index(int id)
{
var user = Db.Users.FirstOrDefault(x => x.Id == id);
if(user != null)
{
return View(user);
}
//Return to the 'Error' view as no user was found
return View("Error");
}
You also need a View to show everything on screen. Make it a strongly typed view, this way you can pass a Model to it. This class will hold all data you want to pass to the view. Code of the view:
//This line lets the view know which class represents the model
#model User
#Html.LabelFor(m => m.Name)
#Html.TextBoxFor(m => m.Name)
#Html.LabelFor(m => m.Name)
#Html.TextBoxFor(m => m.Name)
Using the Razor syntax instead of plain HTML it is very easy to construct and bind your form elements to the corresponding data. In this case the label will show the value of the Display attribute in the User class and the values of the user will be filled in the textboxes.
More reading:
Getting started with ASP.NET MVC 5
ASP.NET MVC Overview
Update:
In case you have a list of objects, you need to enumerate them in the view:
#model IEnumerable<string>
#foreach (var value in Model)
{
<div>#value</div>
}
And if the model is a class and has a property that is a list:
//Let's say a user has lots of names
public class User
{
public int Id { get; set; }
public List<string> Names { get; set; }
}
//View:
#model User
#Html.TextBoxFor(m => m.Id)
#foreach (var name in Model.Names)
{
<div>#name</div>
}
Try to implement a correct ASP.NET MVC architecture. To get this completed, you'll need to use proper Razor (.cshtml type) Syntax in your Views. Best practice:
Create a dedicated ViewModel class in the Model directory. You might call it CustomerCreditTransferViewModel for example. It should contain all Properties you want to display/edit anywhere on the page.
Once you selected your data from your DBContext in your Action, create an instance of CustomerCreditTransferViewModel and populate all fields from the result.
Update your View to use #model CustomerCreditTransferViewModel instead of Swift_MT_103.policy (believe me, this is going to make your live much easier in future)
Copy-paste your raw HTML Code into the page and start looking for all Fields you want to bind, e.g. Text fields (<input type="text" name="accountno" value="" />) and replace them with the Razor Syntax for Data Binding (#Html.TextBoxFor(x => x.AccountNo)). If done correctly, they should be populated now.
Next step is probably the POST. Follow the base MVC Post technique from the Tutorials. Ensure that the Posted Value is of type CustomerCreditTransferViewModel) again, so you can easily validate values and map back to type of Swift_MT_103.policy.

ASP.NET form submit part of a model

This is just something that has been puzzling me, I'm wondering if there's a built in way for this.
Say you have a Package class
public class Package
{
public A AObject { get; set; }
public B BObject { get; set; }
}
And you have a view that uses this Package.
public ActionResult Action()
{
return View(new Package());
}
Now the view will accept this model and have 2 forms.
#model Path.To.Package
#Html.BeginForm("SubmitA", "MyController")
{
#Html.TextBoxFor(m => m.AObject.SomeProperty);
<input type="submit" />
}
#Html.BeginForm("SubmitB", "MyController")
{
#Html.TextBoxFor(m => m.BObject.AnotherProperty);
<input type="submit" />
}
If one would create two actions needed above that take Package as argument, this would work without question...
public JsonResult SubmitA(Package items) { ... }
public JsonResult SubmitB(Package items) { ... }
But at SubmitA the BObject would be null and in SubmitB AObject would be null.
My question here is whether you can submit only a part of the model? So the first form would only submit AObject and the second BObject so you could actually reach these via the following actions:
public JsonResult SubmitA (A a) { ... }
public JsonResult SubmitB (B b) { ... }
You can use the Prefix property of BindAttribute to bind to complex properties of a model. The attribute effectively removes the prefix from the submitted name/value pairs when binding to model.
Your controller methods would be
public JsonResult SubmitA([Bind(Prefix = "AObject")]A model) { ... }
public JsonResult SubmitB([Bind(Prefix = "BObject")]B model) { ... }
You should really use separate view model for each form. You can of course, use bind attribute or use specific property names in the controller action. But, that doesn't solve your real problem. You can only get either of the values and the other object will be unassigned or NULL. This is why you should have separate view model for each view / form. You can build your Package object once you have values for both objects.

Causing problems with foreach into my mvc

This is how I have made a previous post as you can see here.
must retrieve the list from the database
I have tried to make my foreach which have been previously described. but it causes problems for not running my foreach in through while making the mistake on it.
Index.cshtml
#foreach (var u in Model)
{
<div class="col-md-6 col-sm-6">
<div class="plan">
<h3>#u.Name<span>$#u.Price</span></h3>
<p>#u.Text</p>
</div>
</div>
}
and undervisningController.cs
// GET: Undervisning
public ActionResult Index()
{
DatabaseClasseDataContext db = new DatabaseClasseDataContext();
var model = db.Packages.ToList();
return View(model);
}
And the top on index.cshtml have i:
#model MentorOrdblind_MVC.Models.Undervisning.Undervisning
Model Undervisning.cs
public class Undervisning
{
public string Name { get; set; }
public decimal Price { get; set; }
public int Hours { get; set; }
public string Text { get; set; }
}
You are passing your view a List<T> but your model is not a type of IEnumerable. So your view is only expecting a single object of the type Undervisning and not a collection.
Use this:
#model IEnumerable<MentorOrdblind_MVC.Models.Undervisning.Undervisning>
Change your model delcaration to:
#model IEnumerable<MentorOrdblind_MVC.Models.Undervisning.Undervisning>
At this moment your model is a single class, not a list of objects
Always keep in mind what is being passed from controller action to view. If you pass only model from the action then use the model reference in the respective view of the action. If you pass List then use IEnumerable model reference in the view.
If you pass list from action then in the view use:
#model IEnumerable<your model> in the top as reference
If you pass model without a list then use:
#model your model
In your case you are passing list so use IEnumerable of your desired model class.
Thanks

How to persist ICollection entity property between requests in Razor

I am working on ASP.NET MVC 4 application. I use EF 5 and Code First. I have two entities with 1:N relation:
public class Menu
{
//some properties
public virtual ICollection<Document> Documents { get; set; }
}
and:
public class Document
{
//some properties..
public int MenuID { get; set; }
public virtual Menu Menu { get; set; }
}
I have Edit view with [HttpPost] and [HttpGet] methods. When I pass the model through the GET action like this :
Menu model = unitOfWork.MenuRepository.GetById(Id);
if (model != null)
{
return View(model);
}
everything is right, I can see that model contains 1 Documents but then in my razor view if I simply try:
#Html.HiddenFor(m => m.Documents)
then when I submit the form to the Post action I can see that the Documents property is null.
How can keep Documents persistent?
Anything with a collection will not get rendered as you are expecting. you need to create say, a displaytemplate which expects a collection and then render our the properties of the documents in a HiddenFor or if you dont want a display template then do the same but on the view in question.
for example, this is what you need to do:
#for(int counter = 0; counter < Model.Documents; counter++)
{
#Html.HiddenFor(m => Model.Documents[counter].Id)
#Html.HiddenFor(m => Model.Documents[counter].Title)
// and so on
}
so now when you postback, it has all the properties it needs for the engine to bind to and pass it to your controller method and serve it up.
Have you looked through the html, that is generated ? Take a look )
This answer and this one provide workarounds.

Categories

Resources