Dynamically add new fields with Editor Template - asp.net-mvc-4

In my MVC4 project I have a Category view model with a collection of Product view models. I use an Editor Template to render a single Product view model, and pass the collection of Product view models to it:
Category view model:
#model CategoryViewModel
#using MVC4PartialViews.Models.ViewModels
<div class="editor-field">
#Html.EditorFor(model => model.CategoryName)
#Html.ValidationMessageFor(model => model.CategoryName)
</div>
#Html.EditorFor(x => x.Products)
Editor template that renders each Product in the collection:
<div class="editor-field">
#Html.EditorFor(model => model.ProductName)
#Html.ValidationMessageFor(model => model.ProductName)
</div>
// etc.
This works very well as it automagically names and indexes the elements correctly so all the Products get posted back as part of the parent Category view model - here's what it outputs:
<div class="editor-field">
<input class="text-box single-line" id="Products_0__ProductName" name="Products[0].ProductName" type="text" value="Add 1st product for this Category" />
<span class="field-validation-valid" data-valmsg-for="Products[0].ProductName" data-valmsg-replace="true"></span>
</div>
I need to lets users add and remove Products. To add a new one I somehow need to dynamically render the editor template to create the new Product and have each field indexed / named correctly i.e if I already have 2 Products (indexed 0 and 1) then the new Product would need to be named as such:
Products[2].ProductName
I've read this article by Steve Sanderson but it seems clunky and he indexes his fields with a Guid rather than a consecutive index field:
Editing a variable length list in MVC2
TIA

Not to late to answer here,
I am looking for something the link you provide useful to me. Now I know how upload file input can be add dynamically by using add/remove item in IEnumerable property of model in EditorFor.
For your solution, I think UIHint and template can do whatever you wanted to do. Inside the template you can foreach and specify the formatting for id.

Checkout the solution outlined in Jarrett Meyer's blog post, Nested Collection Models in MVC3.
Summarized in this answer on SO.

Related

Is it possible to not omit some opts on the outermost element in a custom Riot tag?

I'm using RiotJS v3.9
I've written a custom tag that accepts a few opts. The problem is that the markup it generates includes all of those opts on the outermost element, in addition to the interior tags where I explicitly deposit them. I do not want any opts to appear on the top element unless I make that happen.
In this case, my custom tag display a list of items. One of the opts it accepts is the value for a specific data- attribute on each list item. So, I want data-something={opts.itemSomething} to appear on each list item, but I do not want that to appear on the wrapper.
// my-list.tag
<my-list>
<ul data-something={ opts.something }>
<li
each={ item in opts.items }
data-something={ parent.opts.itemSomething }
>
{ item }
</li>
</ul>
</my-list>
Using it:
<my-app>
<my-list
something="parent-value"
item-something="child-value"
items={['one', 'two', 'three']}
/>
</my-app>
What it emits into the page:
<my-list something="parent-value" item-something="child-value">
<ul data-something="parent-value">
<li data-something="child-value"> one </li>
<li data-something="child-value"> two </li>
<li data-something="child-value"> three </li>
</ul>
</my-list>
I don't want the emitted <my-list> tag to have either the parent-value or the child-value on it. I only want those attributes to appear on the <ul> and <li>, like I coded it.
// bad output
<my-list something="parent-value" item-something="child-value">
// good output
<my-list>
Is this possible?
Also, I know from working with React that I'm likely to encounter future cases where I want some of the opts to appear on the wrapper while hiding others. So, ideally I'd like to know how to control this behavior on a per-opt basis.
you can remove the unwanted attributes in both the "updated" and "mount" event.
check this demo
However I strongly suggest you to switch to riot#5!!

SelectList dropdown list showing multiple = "multiple" for current viewmodel

This kind of a bizarre issue and I can't figure out a solution how I want.
I'm using .net core 2.1. I have a orders view model like this:
public class OrdersFilterViewModel
{
[Display(Name = "Account Numbers:")]
public IEnumerable<SelectListItem> AccountNumbers { get; set; }
}
My viewmodel and SelectList in my orders controller is called like this:
var vm = new OrdersFilterViewModel
{
AccountNumbers = new SelectList(_context.Account.Where(m => m.UserID == userId), "AccountNumber", "AccountNumber", account)
};
return PartialView("_FilterOrders", vm);
The problem lies when trying to get a dropdown list in the view which looks like this:
<form asp-action="FilterOrders" asp-controller="Order" id="ordersFilterForm" method="post">
<div class="form-group">
<label asp-for="AccountNumbers" class="control-label"></label>
<select asp-for="AccountNumbers" class="form-control" asp-items="#Model.AccountNumbers">
</select>
</div>
<div class="form-group">
<input type="submit" value="Submit" class="btn btn-default" />
</div>
</form>
This somewhat works but gives me a textarea type display where multiple = "multiple" is always tacked on in the browser. I've discovered that if I add something like the following to my viewmodel:
public int? AccountId { get; set; }
Then change my view to:
<select asp-for="AccountId" class="form-control" asp-items="#Model.AccountNumbers">
I can then have my dropdown list. However, I don't need that property for anything as far as I know. I tried a million things so it's possible I made some other slight changes I'm forgetting to get that to work, but that's the gist of it.
Is there any way around adding that extra property? Or do I need it for something I'm not aware of? Or is there any way to set multiple = "false" or something to that effect so I can get my dropdown list with my original viewmodel and such?
I haven't dealt with the post back to the controller yet, so maybe that will reveal the gotchas. I'm basically trying to create a modal type query filter that doesn't really do much other than modify some parameters and send them back to my query to update it. Thanks.
Is there any way around adding that extra property? Or do I need it
for something I'm not aware of?
Yes, you need this extra property, because in your select there are many items, and the user will select one or multiple items, and on the server side you'll need to know what the user selected, this is the purpose of the select tag.
And the multiple = "multiple" depends on what you put in the asp-for in the case of asp-for="AccountId" it is a single int value, so it won't use multiple, is you have an array in the asp-for then it will use the multiple.
Here is a pretty detailed description about the select tag helper:
Select Tag Helper in ASP.NET Core MVC

Changing the class name generated by ClistView Yii

Just a simple question, is it possible to change the classname generated by ClistView ?
by default, it generates
<div class="post">
for all the list.
I'd like to have
<div class=post1>
<div class=post2>
...
You can customize CListView styles with bellow parameters:
$this->widget('zii.widgets.CListView', array(
'dataProvider'=>$YOUR_DATA_PROVIDET,
'itemView'=>'...',
'sortableAttributes'=>array(),
'cssFile'=>' YOU CAN ASSIGN A CSS FILE TO YOUR CLISTVIEW',
'itemsCssClass'=>'SOME CLASS',
'pagerCssClass'=>'SOME CLASS',
'sorterCssClass'=>'SOME CLASS',
'summaryCssClass'=>'SOME CLASS',
));
for more information you can check CListView's Official document in the following link:
CListView
UPDATE:
If you want to change other names, you must edit the source of yii's CGridView. But changing the style of it could be more easier.
If you want a different, incrementing class on each looped list item, change your itemView partial like this:
using the ID of each model:
<div class="post<?php print $data->id; ?>">
<?php
print_r($data->attributes); // Or whatever
?>
</div>
using the 'index' of the current iteration:
<div class="post<?php print $index; ?>">
<?php
print_r($data->attributes); // Or whatever
?>
</div>
More info available here

MVC Sharing strongly typed Partial View

I am trying to render a strongly typed partial view and share it between different parent views.
so I would have a parent view A that is an edit form which has element as well as partial view for Location.
#model Model.Contact
....
#Html.HiddenFor(model => model.LocationID)
#{Html.RenderPartial("../Shared/_Location", Model.Location);}
partial view is an edit form update/insert form
#model Model.Location
....with form elements bound to model passed
<div class="row-fluid">
<div class="span6">
Address 1<br />
#Html.EditorFor(model => model.Address1)<br />
</div>
<div class="span6">
Address 2<br />
#Html.EditorFor(model => model.Address2)<br />
</div>
</div>......
and view B is bounded to different model which also has a need to update Location.
#model Model.JobAssignment
....
#Html.HiddenFor(model => model.OriginLocationID)
#{Html.RenderPartial("../Shared/_Location", Model.OriginLocation);}
It's OriginLocation because this entity has multiple FKs to Location thus I named them differently in CodeFirstMapping
[ForeignKey("OriginLocationID")]
public virtual Location OriginLocation { get; set; }
[ForeignKey("DestinationLocationID")]
public virtual Location DestinationLocation { get; set; }
Database and and Entities are all fine with Fk properly setup to Location by Job and Contact.
What i had before is Location partial view would not get a location entity/model but instead be bound to whatever parent model is like #model Model.Contact just like parent view, that would work fine, as the controls in partial view is prefixed with Location.* and Location_* for ID and it works its magic, having controls as: #Html.EditorFor(model => model.Location.Address1)
but im trying to share the location partial view just like I used to do with UserControls in asp.net, so want to bind it to
I cannot get it to work, the closest I get is to bound the data, but on edit/save I get strange error.
"A referential integrity constraint violation occurred: A primary key property that is a part of referential integrity constraint cannot be changed when the dependent object is Unchanged unless it is being set to the association's principal object. The principal object must be tracked and not marked for deletion."
Please Please somebody point me to the right direction!

need rails like form_for tag in Rhodes

I was wondering if I can have something like form_for tag instead of the html tag in the edit.erb page in Rhodes. Because I have a Counter model with two attribs which I want to update them seperately based on the button pressed which resides right beside the value. I was able to do it in rails using the <%= form.submit 'up_a' %> & check which button was pressed in update method, like:
def update
#counter = Counter.find(params[:id])
if params[:commit] == 'up_a'
update_attri1 # simple increment method for attrib 1
elsif params[:commit] == 'up_b'
update_attri2 # simple increment method for attrib 2
end
end
and call that method to update that value.
So I want to have more control on what attribs I want to update based
on the clicks in form. Is there anyway I can achieve this in Rhodes?
EDIT :
The general problem seems to be that you want two submit buttons in a single form, each of which should do two slightly different things.
In the case that you only have two different values and one submit button for each, the simplest solution would be simply to make two forms that both call the update def (through their action-attribute), but each with their specific value of the query-parameter (in this case "commit"). These calls would have the following form:
<form method="POST" class="myForm" action="<%=url_for :controller => :Counter, :action => :update, :query => {:commit => 'up_a'}%>">
However, if you only want a single form (possibly also with many other input-values) there are several different ways to do it. In the following you will see a detailed implementation of one way to do it.
In this solution your buttons should NOT be submit buttons, but regular buttons (exactly how they are made with jQuery Mobile).
In order to make this solution work, you will need to use some javascript. You should therefore add the following javascript functions to your application.js and include it in your layout.erb.
function submitForm(formClass){
var activeForm = 'div.ui-page-active '+formClass;
$(activeForm).submit();
}
function callCounterSetUpdateAction(c){
$.get('/app/Counter/setUpdateAction', { commit: c});
}
Now that we have the needed javascript functions in place, lets take a look at edit.erb.
In this example Counter have three different attributes: a, b and c. We will however, only pay attention to a and b to begin with.
The form in your edit.erb file should be similar the implementation below. Notice, that the form actually doesn't have a submit button (as we will see later, the submit is actually made through our javascript function submitForm(formClass)).
<form method="POST" class="myForm" action="<%= url_for :action => :update %>">
<input type="hidden" name="id" value="<%= #counter.object %>"/>
<div data-role="fieldcontain">
<label for="counter[a]" class="fieldLabel">A</label>
<input type="text" id="counter[a]" name="counter[a]" value="<%= #counter.a %>" <%= placeholder( "A" ) %> />
</div>
<div data-role="fieldcontain">
<label for="counter[b]" class="fieldLabel">B</label>
<input type="text" id="counter[b]" name="counter[b]" value="<%= #counter.b %>" <%= placeholder( "B" ) %> />
</div>
<div data-role="fieldcontain">
<label for="counter[c]" class="fieldLabel">C</label>
<input type="text" id="counter[c]" name="counter[c]" value="<%= #counter.c %>" <%= placeholder( "C" ) %> />
</div>
<a data-role="button" data-transition="none" href="javascript:callCounterSetUpdateAction('up_a');">Update A</a>
<a data-role="button" data-transition="none" href="javascript:callCounterSetUpdateAction('up_b');">Update B</a>
</form>
Now that we have defined our view (edit.erb) lets take a look at the definitions we need our controller.
Firsly, as it can be seen from the href attribute on the buttons, what actually happens once we press a button is that it calls a javascript function which in turn calls the following def in the controller:
def setUpdateAction
$pressedButton = #params['commit']
WebView.execute_js("submitForm('.myForm');")
end
The purpose of this def is to store the parameter we sent from our button and then submit the form on the active page. Notice here that we added a class called myForm to the form shown above. You should also notice that we ensure that only the form on the active page is selected by adding 'div.ui-page-active ' to our formClass in the jQuery selection.
Finally, lets take a look at how your update definition should look like:
def update
#counter = Counter.find(#params['id'])
c = #params['counter']
if #counter
if $pressedButton == 'up_a'
# Update value A.
#counter.update_attributes(
{"a" => c['a']}
)
elsif $pressedButton == 'up_b'
# Update value B.
#counter.update_attributes(
{"b" => c['b']}
)
end
end
redirect :action => :index
end
It should be noticed here that we select which attributes to update based upon the $pressedButton variable we assigned through setUpdateAction. As a final comment we could also update multiple attributes as seen below (where we also update the 'c' attribute).
#counter.update_attributes(
{"b" => c['b'],"c" => c['c']}
)