I'm doing a page to edit a product,the product have some characteristics,i'm using a getAll to recover all of the characteristics.
model.Listcharacteristics= v_ProdutoCharacteristicsMetodos.GetAll(EmpresaId)
.Select(x => new ProdutoCharacteristicsModel()
{
Apagado = x.Apagado,
DeAte = x.DeAte,
DepartamentoId = x.DepartamentoId,
Descricao = x.Descricao,
Description = x.Description,
Fator = x.Fator,
Keywords = x.Keywords,
MostrarHome = x.MostrarHome,
NCM = x.NCM,
Ordem = x.Ordem,
PessoaId = x.PessoaId,
ProdutoFamiliaId = x.ProdutoFamiliaId,
UrlImagem = x.UrlImagem
})
.ToList();
But i have a method that can get the product characteristic by the product ID,so in the edit page,i need to show the currently characteristic instead of the default value,how i can select which value show first select in the dropDowList?
In the BLL i created this.
model.Produto.ProdutoFamilia = v_ProdutoFamiliaMetodos.GetById(produtoempresa.ProdutoFamiliaId).Descricao;
I'm passing produtoempresa (The product)and ProdutoFamiliaId is the caractheristic ID,i'm getting a string with the name of the characteristic,this name its what i have to show the default value.
The html is this.
<tr>
<td>
#if (this.Model.ListFamilia != null && (this.Model.ListFamilia.Count > 0))
{
for (int i = 0; i < Model.ListFamilia.Count; i++)
{
#Html.HiddenFor(model => model.ListFamilia[i].ProdutoFamiliaId)
#Html.HiddenFor(model => model.ListFamilia[i].Descricao)
}
}
#Html.DisplayNameFor(model => model.Produto.ProdutoFamiliaId)*
</td>
<td>
#Html.DropDownListFor(model => model.Produto.ProdutoFamiliaId, new SelectList(Model.ListFamilia, "ProdutoFamiliaId", "Descricao", Model.Produto.ProdutoFamiliaId), String.Empty)
</td>
</tr>
In the dropdowList the default value showing must be the model.Produto.ProdutoFamilia.
You usually render the dropdown box and set the selected value in the html. This is done with the
<select name="hall" id="hall" value="3">
<option selected="selected">1</option>
<option>2</option>
<option>3</option>
</select>
This will have the first option selected in your dropdown list. From your method that can get the product characteristic you should be able to calculate which option you want to append
selected="selected"
Hope this helps
Related
In my MVC application I have a view where I will display different data from a SQL table. This will generate different amount of drop down lists and text boxes, depending on what is passed in from the Model.
My issue is if I want to then use that data I can't seem to figure out how I can relate control X to object Y in SQL. For example, if I have 2 textboxes that I want to do an update on, then when the Post happens in my application the FormCollection parameter will let me see the Value of the objects, but not their control name or any form of identifying factor.
I could set the Value to a combination of the entered value + a name, then split this, but it seems very much like a lazy workaround.
I've tried to assign an ID to each, for example:
#foreach (DataObject item in Model.AllDataObjects)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.Name)
</td>
<td>
#Html.DisplayFor(modelItem => item.Data)
</td>
<td>
#if (item.Rule.Contains("Yes;No"))
{
#Html.DropDownListFor(model => item.Value, new List<SelectListItem>
{
new SelectListItem {Text="Yes", Value="Yes"},
new SelectListItem {Text="No", Value="No" }
}, new { #id = item.ObjectId });
}
else
{
#Html.TextAreaFor(model => item.Value, new { style = "width: 400px;", #rows = 5, #id = item.ObjectId })
}
</td>
</tr>
}
Edit: The following is my Post ActionResult method in the Controller, albeit it isn't complete as I can't figure out how to get an ID for the control from the FormCollection
[HttpPost]
[ValidateInput(false)]
public ActionResult UpdateData(FormCollection collection, int objectId=0)
{
try
{
int propertyTypeId = 0;
string propertyValue = string.Empty;
// Get all the control values from the collection
string[] allValues = new string[] { };
IValueProvider valueProvider = collection.ToValueProvider();
foreach(string key in collection.Keys)
{
ValueProviderResult result = valueProvider.GetValue(key);
allValues = result.RawValue as string[];
}
ObjectData objectData = _execution.GetObjectDetails(0);
UpdateDataResponse result = _execution.UpdateData(0, objectId,
objectValue, UserName);
return RedirectToAction("Details",
new { ObjectId = objectData.ObjectId, error = result.ErrorMessage });
}
catch (Exception ex)
{
// My exception handling here
}
}
So I can see in the mark-up that the controls are assigned the object ID as their own ID, but how can I get this back? When I check FormCollection I only see the values for each control, but no way of identifying which is which.
Edit: I'm using MVC version 4.
A form only submits the values of its successful controls (as name/value pairs based on the controls name and value attributes) so if you do not generate a control for the ObjectId properties, they will not be submitted.
However, you current use of foreach loop will not allow you to obtain any meaning information from the data which is posted because all your names are identical and there is no way to reliable match up which value belongs to which item in the collection. Instead use a for loop or EditorTemplate in the view and bind to your model, rather than using FormCollection.
The view should be
#for (int i = 0; i < Model.AllDataObjects.Count; i++)
{
<tr>
<td>#Html.DisplayFor(m => m.AllDataObjects[i].Name)</td>
<td>#Html.DisplayFor(m => m.AllDataObjects[i].Data)</td>
<td>
#Html.HiddenFor(m => m.AllDataObjects[i].ObjectId)
#if (Model.AllDataObjects[i].Rule.Contains("Yes;No"))
{
#Html.DropDownListFor(m => m.AllDataObjects[i].Value, new SelectList(new string[]{ "Yes", "No" }));
}
else
{
#Html.TextAreaFor(m => m.AllDataObjects[i].Value, new { style = "width: 400px;", #rows = 5 })
}
</td>
</tr>
}
And assuming the model in the view is #model MyModel, change the POST method to
[HttpPost]
[ValidateInput(false)]
public ActionResult UpdateData(MyModel model)
and the value of model.AllDataObjects will contain a collection with its ObjectId and Value properties correctly bound.
For more information on why using a foreach loop will not work, refer to this answer.
I can't get the selected values from the following dropdownlist, here how I generate the list:
In the repository:
public IQueryable<OhaType> GetAllOhaTypes ()
{ return db.OhaType.OrderBy(d => d.Name); }
In the controller:
....
var OhTypes = _medicationRepository.GetAllOhaTypes();
ViewBag.OhTypes = new SelectList(OhTypes, "OhaTypeId", "Name");
.....
In the View:
#foreach (var item in this.Model.OhaMedication)
{
<tr>
<td>
#(Html.Bootstrap().DropDownList("OhaTypeId", (SelectList)ViewBag.OhTypes)
.HtmlAttributes(new
{
Name ="OhaTypeId",
style = "width: 300px;"
}).Size(InputSize.Small)
.Class("form-group input-sm").Id("OhaTypeId")
.ShowValidationMessage(true))
</td>
.....
I get the first item of the list displayed not the correct value. I get the correct values in other fields from the table.
I also tried "#HTML.DropdownList(...)", same issue.
Would appreciate your suggestions.
Can't seem to get the list to remove the correct item.
I've put breakpoints in the code to test if the id is the correct index with shipment.shipmentfreight[id] within the Immediate Window and it shows the correct list item, but it always removes the last item.
In my view model I have a list of ShipmentFreightLine declared as:
public List<ShipmentFreightLine> shipmentfreight { get; set; }
I have a call back that removes the line that returns the new partial view:
public virtual ActionResult ShipmentNewFreightLineRemove(int id,NewShipment shipment)
{
int cnt = shipment.shipmentfreight.Count();
if (id >= 0 && cnt != 1 && id <= cnt)
{
shipment.shipmentfreight.RemoveAt(id);
//shipment.shipmentfreight.RemoveAt(shipment.shipmentfreight.IndexOf(shipment.shipmentfreight[id]));
//shipment.shipmentfreight.Remove(shipment.shipmentfreight[id]);
//shipment.shipmentfreight[id]
}
return PartialView("ShipmentNewFreightLineEdit", shipment);
}
As you can see I've commented out different variations that I have tried and each one removes the last item in the list.
What am I missing?
I am coding in VS2012 ASP.NET MVC using C#.
Any help would be aprreciated
As requested by Kirk the id field is from an anchor
Remove
Which calls this javascript function
function RemoveFreightLine(index) {
var ShipmentData = $('#fShipmentNew').serialize();
var url = "/Tracking/ShipmentNewFreightLineRemove/" + index
$.post(url, ShipmentData,
function (data) {
$("#dNewFreightLines").html(data);
});
}
These all have the correct id in them so i don't believe its the cause
I traced the view and found that it is removing the correct item in the list but the view is showing the old data
<table id="tFreight" class ="tblFreight">
<tbody>
#for (int i = 0; i < Model.shipmentfreight.Count; i++)
{
<tr>
<td>#(i+1)</td>
<td>#Html.TextBoxFor(m => m.shipmentfreight[i].Pieces, new { autocomplete = "off", #Class = "txtboxsmall",maxlength ="3"})</td>
<td>#Html.TextBoxFor(m => m.shipmentfreight[i].Description,new { autocomplete = "off", #Class = "txtareasmall"})</td>
<td>#Html.TextBoxFor(m => m.shipmentfreight[i].WeightPerPiece, new { autocomplete = "off", #Class = "txtboxsmall",maxlength ="3"})</td>
<td>#Html.TextBoxFor(m => m.shipmentfreight[i].ActualWeight, new { autocomplete = "off", #Class = "txtboxsmall",maxlength ="3"})</td>
<td>#Html.TextBoxFor(m => m.shipmentfreight[i].Length, new { autocomplete = "off", #Class = "txtboxsmall",maxlength ="3"})</td>
<td>#Html.TextBoxFor(m => m.shipmentfreight[i].Width, new { autocomplete = "off", #Class = "txtboxsmall",maxlength ="3"})</td>
<td>#Html.TextBoxFor(m => m.shipmentfreight[i].Height, new { autocomplete = "off", #Class = "txtboxsmall",maxlength ="3"})</td>
<td>Remove</td>
<td>#Model.shipmentfreight[i].Description</td>
</tr>
}
</tbody>
</table>
The last cell was for debugging purposes and does display the correct information.
I am thinking its some quirk with TextBoxFor that I don't know about.
Basically the last cell is showing the correct data from the new list but anything in the TextBoxFor is showing the old list data.
Any ideas on why I am getting this behavior?
Looks like this was a problem with the ViewData and not the List.
This seems to fix the problem:
ViewData = null;
or
ModelState.Clear();
Found the answer with Why won't a List of complex types bound to TextBoxes in a table show changes to the model in MVC 4? and TextBoxFor Helper retains previous value even when model value is empty
As with all things...Finding the real cause is key to finding the answer.
What I am trying to achieve is hard to explain, so please let me know if I can provide more information. I have a feeling that I am trying to use WebGrids beyond their means, so if anyone has any open source alternatives that would do what I am trying, that would also be helpful.
I need to build a WebGrid from the ground up, because the content returned to it (columns and values) changes depending on other criteria on my form. I have this working in a few simple lines of code in a Table, but I wanted to use WebGrid for the styling, sorting and paging.
#model DocumentSearchViewModel
#if ((this.Model != null) && (this.Model.SearchResults != null) && (this.Model.SearchResults.Count() > 0))
{
<table>
<thead>
<tr>
<th>Document</th>
#foreach (var metadata in this.Model.SearchResults.Metadata)
{
<th>
#metadata.InstanceFieldName
</th>
}
</tr>
</thead>
<tbody>
#foreach (var document in this.Model.SearchResults)
{
<tr>
<td>
#Html.ActionLink(document.Id.ToString(), "Details", new { id = document.Id })
</td>
#foreach (var metadata in document.Metadata)
{
<td>
#metadata.Value
</td>
}
</tr>
}
</tbody>
</table>
}
So to explain the model structure, The SearchResults has an IEnumerable<MetadataModel>, and this MetadataModel has properties of InstanceFieldName and Value. When a search is performed, every result will always have the same number of Metadata, and the same InstanceFieldNames, but different values, however a quick change of a field on the form, and a new search could return a new set of results (Again with the same set of Metadata as each other, but different to the first set of results)
The columns of the grid correspond to the Metadata InstanceFieldName, and the content the Value.
So I have made my best attempt using WebGrid, but the best I can get is a grid with the right column headers, and the right number of rows, the columns have the right data, but each row is the same (copied from the last row).
#{
var grid = new WebGrid(canPage: true, canSort: true, rowsPerPage: Model.PageSize, sortFieldName: Model.Sort, sortDirectionFieldName: Model.SortDir);
grid.Bind(Model.SearchResults, rowCount: Model.DocumentCount);
List<WebGridColumn> cols = new List<WebGridColumn>();
foreach(var metadata in Model.SearchResults.Select(r => r.Metadata).FirstOrDefault())
{
var col = new WebGridColumn();
col.ColumnName = metadata.InstanceFieldName;
col.Header = metadata.InstanceFieldHeader;
col.Style = "gridRow";
col.CanSort = true;
cols.Add(col);
}
foreach (var result in Model.SearchResults)
{
foreach (var col in cols)
{
var metadataValue = result.Metadata.Single(m => m.InstanceFieldName == col.ColumnName).Value;
col.Format = (item) => #Html.Raw("<text>" + metadataValue + "</text>");
}
}
}
#if ((this.Model != null) && (this.Model.SearchResults != null) && (this.Model.SearchResults.Count() > 0))
{
#grid.GetHtml(htmlAttributes: new { id = "documentGrid" }, rowStyle: "gridRow", alternatingRowStyle: "gridRowAlt", columns: cols)
}
What I'm trying to work out is how and if possible to generate the columns first, and then populate the rows into these columns.
Any help is really appreciated, thanks, Mark
You are feeding the rows with the same value, you should change the Format:
col.Format = (item) => #Html.Raw(item.metadataValue);
Here is what my view looks like:
#model Affiliate
<div class="box paint color_16">
<div class="title">
<h4><i class="icon-tasks"></i><span>#Model.CompanyName's Commissions</span> </h4>
</div>
<div class="content top ">
<div class="subtitle">
#Html.ActionLink("Void", "DeleteInvoice", new { commList = "??", affId = Model.Id }, new { #class = "btn" })
#Html.ActionLink("Create Invoice", "CreateInvoice", new { commList = "??", affId = Model.Id }, new { #class = "btn" })
#Html.ActionLink("Pay", "PayInvoice", new { commList = "??", affId = Model.Id }, new { #class = "btn" })
</div>
<table class="table table-striped table-hover">
<tr>
<h3>Commissions</h3>
</tr>
<tr>
<td></td>
<td>Amount</td>
<td>Status</td>
<td>Action</td>
</tr>
#foreach (var item in Model.Commissions)
{
<tr>
#if (item.Status == ViewBag.PaymentStatus || ViewBag.PaymentStatus == "All")
{
<td>#Html.CheckBox("commId", new { value = item.Id })</td>
<td>#Html.DisplayFor(x => item.PayoutAmount)</td>
<td>#Html.DisplayFor(x => item.Status)</td>
}
</tr>
}
</table>
</div>
What I want to be able to do is when I hit an actionlink on the top, grab all the items from the table that are checked, and pass that list of id's to the controller logic. I am assuming a viewmodel may be the solution, something like this:
public Affiliate affilite { get; set; }
public List<int> selectedItems { get; set; }
etc.
But how to I get the selected Items into that VM selectedItems container?
Based off your comments, you don't seem to be looking for the most "correct" answer, but rather just a quick and dirty "how would I do this" answer. If you just want to pass the list, you could setup your controller action like this:
public ActionResult MyAction(int[] id)
{
...
}
Or, you seem to indicate it is strongly typed to a view model with a property that contains a List (I would shorten the name of the property, you'll see why in a second).
In javascript, the easiest thing to do would be to use jQuery to bind a click event on your hyperlink that gets the list of items that are checked and appends that to the query string.
$("#myLink").click(function()
{
var url = "site.com/action?";
var ids = $(".table").find("input:checked");
ids.each(function()
{
url += "id=" + $(this).val() + "&"
});
window.location = url;
});
Basically, you want to create one long query string with the action parameter's name repeated over and over, which identifies an array. It looks something like this (id is for int[] id in MyAction):
id=15&id=20&id=25&id=30&....
And then once the query string is built, redirect the user to that url. MVC should then be able to bind that to an array and you're all set.
That's basically the idea, anyway; the syntax and the javascript I wrote could be way off so don't copy my code and expect it to work as is - I wrote that off the top of my head. If your action is bound to a viewmodel, then you need to set the parameter in the query string to the name of the property of your model:
selectedids=1&selectedids=2&selectedids=3...
Or, if the array is a property of an object, which is a property of the model...
model.selectedids=1&model.selectedids=2&model.selectedids=3...
You'll just need to play around with it some.
Use html checks inside form tag ( you could use helpers too) and post the model to a post action.
MVC will serialize the model automatically