I'm generating a list of rss links in my model that I want to show on my webpage. The model works fine and the display of the links works fine on the view. My question is this, I'd like to display the links in 2 side by side columns. The first 5 links in the first column and the next 5 links in the second column. Right now I'm showing all 10 links in each column. I'm sure there is an easy way to do this, but I'm just not sure how. Any help would be appreciated.
Here is my model:
namespace OA.Models
{
public class Rss1
{
public string Link { get; set; }
public string Title { get; set; }
public string Description { get; set; }
}
public class Rss1Reader
{
private static string _blogURL = "http://www.test.com/blogs/news/feed/";
public static IEnumerable<Rss1> GetRss1Feed()
{
XDocument feedXml = XDocument.Load(_blogURL);
var feeds = from feed in feedXml.Descendants("item")
select new Rss1
{
Title = feed.Element("title").Value,
Link = feed.Element("link").Value,
Description = Regex.Match(feed.Element("description").Value, #"^.{1,180}\b(?<!\s)").Value
};
return feeds;
}
}
}
Here is my view:
#model IEnumerable<OA.Models.Rss1>
<table style="width: 80%;margin-left: auto;margin-right: auto;margin-top:10px;margin-bottom:25px;">
<tr>
<td>
<div id="RSSCOL1">
<span style="font-size:.9em;">
#foreach (var item in Model)
{
#item.Title<br />
}
</span>
</div>
</td>
<td>
<div id="RSSCOL2">
<span style="font-size:.9em;">
#foreach (var item in Model)
{
#item.Title<br />
}
</span>
</div>
</td>
</tr>
</table>
The quickest way to accomplish this is to update your first and second loops to this...
#foreach (var item in Model.Take(Model.Count()/2))
...
#foreach (var item in Model.Skip(Model.Count()/2))
However, you might want to consider one loop that displays an unordered list, then using css to lay it out into columns. What if someone is looking at your page on a phone vs a 27-inch screen? You may want the columns to display differently. Good luck! See this link: How to display an unordered list in two columns?
Related
I have these 2 models:
public class Invoice
{
public string InvoiceID {get; set; }
public List<InvoiceElement> InvoiceElements {get; set;}
[...other fields...]
}
public class InvoiceElement
{
public string InvoiceElementID {get; set; }
[ForeignKey("Invoice")]
public string InvoiceID { get; set; }
public virtual Invoice Invoice { get; set; }
public string Item {get; set;}
[...other fields...]
}
I am unable to make a CREATE view for new Invoices that lets me add InvoiceElements.
I want to have a "CurrentInvoiceElements" table where to dinamically add rows.
Just trying to making it simple. You can use the name attribute (the attribute that asp.net uses for modal binding) and post a list along with other properties of the class. You can use javaScript to append new elements to your form. Using the above modals you've provided, I have written a simple example using simple jQuery functions.
Razor View:
<button class="btn btn-success" id="add_btn">Add Invoice Element</button>
#using (#Html.BeginForm("SaveInvoice", "Invoice", FormMethod.Post))
{
<!--Other modal attributes inputs goes here -->
<!--You can use normal html helper extensions -->
<table id="element_table">
<thead>
<tr>
<td>Element Id</td>
<td>Item</td>
</tr>
</thead>
<tbody>
<tr>
<td><input name="invoice.InvoiceElements[0].Item" id="InvoiceElements[0].Item" /></td>
<td><input name="invoice.InvoiceElements[0].InvoiceElementID" id="InvoiceElements[0].InvoiceElementID" /></td>
</tr>
</tbody>
</table>
<input type="submit" />
}
JavaScript:
<script type="text/javascript">
$("#add_btn").on('click', function (e) {
var table = $("#element_table");
var idx = $(table).find("tbody>tr").length;
var htmlToAppend = `<tr>
<td><input name="invoice.InvoiceElements[${idx}].Item" id="InvoiceElements[${idx}].Item" /></td>
<td><input name="invoice.InvoiceElements[${idx}].InvoiceElementID" id="InvoiceElements[${idx}].InvoiceElementID" /></td>
</tr>`;
$(table).find("tbody").append(htmlToAppend);
});
</script>
Controller / Action:
[HttpPost]
public ActionResult SaveInvoice(Invoice invoice)
{
/* your logic here */
if(ModelState.IsValid)
_invoiceBusiness.SaveInvoice(invoice);
return View();
}
Please make sure the variable name in the parameter of the action method matches the name used in the name attribute of the input tag. i.e. name = "invoice.***" public ActionResult SaveInvoice(Invoice invoice)
I followed this solution: https://github.com/danludwig/BeginCollectionItem some years ago, and worked fine.
If I'm not mistaken, at the time I managed to do it using only the HTML Helper: HtmlPrefixScopeExtensions. Then just make sure the name you give on your View when you do Html.BeginCollectionItem("name") is exactly the same as your collection on your ViewModel.
That's for binding back to the controller.
With this, you can dynamically add rows using AJAX per example.
I hope it's clear enough. If you don't understand it I may make a Github repository with this.
This question already has answers here:
Submit a List from View to Controller
(2 answers)
Closed 5 years ago.
View has a list of items, each with a checkbox. Purpose of the form is to check the boxes then return the list to the db. I expect to see the PickList model in the ViewModel populated with the hidden seedid and the checkbox values, but the form always submits with the PickList as null.
#model Inventory.ViewModels.ExtractionViewModel
<div class="col-md-4">
<button class="btn btn-primary" type="submit" form="pick-list-form">Update Pick List</button>
</div>
#using (Html.BeginForm("UpdatePickList", "Extraction", FormMethod.Post, new { #id = "pick-list-form" }))
{
<table class="table">
<tr>
<th>
Seed Reference
</th>
<th>Extracted?</th>
</tr>
#foreach (var item in Model.PickList)
{
<tr>
<td>
#Html.HiddenFor(modelItem => item.ExtractionId)
#Html.HiddenFor(modelItem => item.SeedId)
#Html.DisplayFor(modelItem => item.SeedId)
</td>
<td>
#Html.CheckBoxFor(modelItem => item.IsExtracted)
</td>
</tr>
}
</table>
}
View Model
public class ExtractionViewModel
{
public ExtractionDTO Extraction{ get; set; }
public List<PickListDTO> PickList { get; set; }
}
Pick list model
public class PickListDTO
{
public int ExtractionId { get; set; }
public int SeedId { get; set; }
public bool IsExtracted { get; set; }
}
Using #Html.DisplayFormay cause the model to be sent back as NULL. You can use #Html.TextBoxFor.
And just to remind:
Use HiddenFor when you want to provide posted data that the user does not need to be aware of.
Use DisplayFor when you want to show records but not allow them to be editted.
Use TextBoxFor when you want to allow user input or allow the user to edit a field.
I hope it helps you!
I'm new to MVC. I'm trying to build a small website for people to pick winners in NFL games. I am confused on how to translate what a user picks in the view to the data in my database. I am using MVC 5 and Entity Framework 6.
I want the view to list each game, displaying the home team and the away team. Next to each team there is a radio button. The user selects the radio button next to each selection, and then clicks a Submit button. For each game, I want to read which of the two radio buttons has been selected, and then write the name of the related team to a database table for Picks. The database is already built and I can't change it.
So I have a model for Picks (id, week_number, game1, game2, etc). I have a model for Schedule, which is all of the NFL games this season (id, week_number, game_number, home, away). I have the basic controller from scaffolding it out, and I am trying to create a ViewModel to combine the two models for my what my view needs.
What I do not know how to do is add a radio button so that it is tied to the team name it is next to, so that when I submit it will be determined if that button is checked, and if so, to write that team name to the database. Am I supposed to make 32 boolean properties for each radio button and then if it is checked look up the team name in a list of all the games? It seems like this should be much easier, but I am stumped with the whole MVC structure.
Also, is this supposed to happen in the controller, and not the view model? How do I access which radio button is selected?
UPDATE
I followed the suggestions here as best I could, and I am closer. But the problem now is that all of the radio buttons on the page are in one radio button group - that is, only one button can be selected. I want to have each row in the table be a group, so that ultimately there will be 16 buttons selected. Here are the models and view I am using:
public class GameViewModel
{
public string AwayTeam { get; set; }
public string HomeTeam { get; set; }
public string SelectedTeam { get; set; }
public GameViewModel()
{
AwayTeam = string.Empty;
HomeTeam = string.Empty;
SelectedTeam = string.Empty;
}
public GameViewModel(string away, string home)
{
AwayTeam = away;
HomeTeam = home;
SelectedTeam = string.Empty;
}
}
public class WeeklyPicksViewModel
{
private NFLEntities db = new NFLEntities();
public int MNFscore { get; set; }
public List<GameViewModel> WeeklySchedule { get; set; }
public int WeekNumber { get; set; }
public WeeklyPicksViewModel(List<schedule> weeklySchedule, int userid)
{
List<GameViewModel> week = new List<GameViewModel>();
foreach (var game in weeklySchedule)
{
GameViewModel g = new GameViewModel(game.away, game.home);
week.Add(g);
}
WeeklySchedule = week;
}
}
#model FootballPickEm.ViewModels.WeeklyPicksViewModel
<h2>Picks Page</h2>
<hr />
<div>
<table>
#foreach (var game in Model.WeeklySchedule) {
<tr>
<td>
#Html.RadioButtonFor(m => game.SelectedTeam, game.AwayTeam)
</td>
<td>
<img src="~/images/#(game.AwayTeam.ToLower()).gif" />
</td>
<td>
#Html.DisplayFor(m => game.AwayTeam)
</td>
<td>
AT
</td>
<td>
#Html.RadioButtonFor(m => game.SelectedTeam, game.HomeTeam)
</td>
<td>
<img src="~/images/#(game.HomeTeam.ToLower()).gif" />
</td>
<td>
#Html.DisplayFor(m => game.HomeTeam)
</td>
</tr>
}
</table>
</div>
Good news. You don't need to create 32 bools. You can just create one string (or enum or whatever else) that represents the team. If you call the property team, you can generate radio buttons like this.
<label><input type="radio" name="team" value="piggers">The Piggers</label>
<label><input type="radio" name="team" value="dogcatchers">The Dogcatchers</label>
Then when you submit the form, your team property will contain a value like "piggers".
I am looking for help on how to add a new row of LineItems to an Invoice in a create Razor view of an ASP.Net MVC 5 application. I have read almost all similar questions but none have addressed what I thought was a simple use case.
Here is my Invoice model class
public class Invoice
{
public int Id { get; set; }
public int InvoiceNumber { get; set; }
public List<LineItem> LineItems { get; set; }
public Client Customer { get; set; }
public DateTime DateCreated { get; set; }
public decimal Total { get; set; }
public Invoice()
{
LineItems = new List<LineItem>();
}
Take note that this invoice contains a List of LineItems and each line Item is a simple object. And a List of line items is created in the Invoice constructor. Here is the LineItem model class
public class LineItem
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public int Quantity { get; set; }
public decimal Price { get; set; }
public decimal Total { get; set; }
}
The generated ASP.Net MVC 5 Razor views did not recognize the LineItems list of the object and did not create any entry for it. I want to dynamically add a row to the table below and I want to make that row an instance of Line items.
Here is the Table showing the invoice
<table class="table table-condensed" id="invoiceTable">
<thead>
<tr id="invoiceTableHead">
<td><strong>Item Name</strong></td>
<td class="text-center"><strong>Item Description</strong></td>
<td class="text-center"><strong>Item Price</strong></td>
<td class="text-center"><strong>Item Quantity</strong></td>
<td class="text-right"><strong>Total</strong></td>
</tr>
</thead>
<tbody>
And here is my attempt at using JQuery to append a row to this table dynamically and I that is where I am stuck, any help or pointers that will be greatly appreciated.
<script type="text/javascript">
$("#lineItemButton").click(function () {
debugger;
// Create elements dynamically
var newRow = "<tr><td>'#Html.TextBoxFor(x => x.LineItems, new { ??? What do int public here)'</td></tr>";
// Add the new dynamic row after the last row
$('#invoiceTable tr:last').after(newRow);
});
</script>
You can create dynamic rows, but from my experience they will not bind to the model. I have a drop down that the user selects an asset number and clicks an 'Add' button that adds a new row, dynamically, to the table.
What I did was create a hidden row in a table to use a template.
<table class="table table-bordered table-condensed table-hover" id="lineItemTable" name="assetTable">
<thead>
<tr>
<th class="text-center">Item #</th>
<th class="text-center">Asset</th>
<th class="text-center">Condition</th>
<th class="text-center">Description 1</th>
<th class="text-center">Description 2</th>
<th class="text-center">Inventory Num</th>
<th class="text-center">Serial Number</th>
</tr>
</thead>
<tbody>
<tr hidden>
<td>
<label id="row"></label>
</td>
<td>
<input asp-for="TransferLineItem.AssisAsset" class="form-control" value=#ViewBag.AssisAsset />
</td>
<td>
<select asp-for="TransferLineItem.Condition" class="form-control" asp-items="#ViewBag.Conditions"></select>
</td>
<td>
<input asp-for="TransferLineItem.AssetDescription1" class="form-control" value=#ViewBag.AssetDescription1 />
</td>
<td>
<input asp-for="TransferLineItem.AssetDescription2" class="form-control" value=#ViewBag.AssetDescription2 />
</td>
<td>
<input asp-for="TransferLineItem.InventoryNum" class="form-control" />
</td>
<td>
<input asp-for="TransferLineItem.SerialNumber" class="form-control" value=#ViewBag.SerialNum />
</td>
</tr>
</tbody>
</table>
When the add button is clicked I use jQuery to clone the hidden table row and append the table with the new row. I append the id of each control with '_[row number]' so that each control had a unique id number.
//clones the first row of the table
var newRow = $("#lineItemTable tbody tr").first().clone();
//removes the 'hidden' attribute so it will be visible when added to the table
newRow.removeAttr("hidden");
//add/append new row to the table
$("tbody").append(newRow);
//get row number which will be appended to the id of each control in this row
//for example if this were the second row then the id of the asset field would be something like asset_2.
//note that since there is already a hidden row in the table, we subtract 1 from the row number
var rowNum = "_" + ($("#lineItemTable tbody tr").length-1);
//loop through the input controls and add the new id value
newRow.find("input").each(function () {
// get id of the input control
var ctrl = $(this).attr("id");
//concatenate the row number to the id
var newId = ctrl + rowNum;
//assign new id to control
$(this).attr("id", newId);
});
To save the data in the html table, I use jQuery to create an array of name-value pairs for each row, and pass that to a function in the controller.
//get table
var tbl = document.getElementById("lineItemTable");
//array to hold the json objects
var jsonArray = [];
//iterate through the fields and put values in the json object
for (var i = 1, r = tbl.rows.length-1; i < r; i++)
{
var jsonObj = {
asset: $("#TransferLineItem_AssisAsset_" + i).val(),
condition: $("#TransferLineItem_Condition_" + i).val(),
assetDescription1: $("#TransferLineItem_AssetDescription1_" + i).val(),
assetDescription2: $("#TransferLineItem_AssetDescription2_" + i).val(),
InventoryNum: $("#TransferLineItem_InventoryNum_" + i).val(),
serialNumber: $("#TransferLineItem_SerialNumber_" + i).val()
};
//put json object in array
jsonArray.push(jsonObj);
}
//pass json array to controller function to save line items
$.ajax({
type: "GET",
url: "Create?handler=SaveTransferLineItems",
contentType: "application/json; charset=utf-8'",
data: { jsonObj: JSON.stringify(jsonArray) },
success: function () {
showModal("btn-success", "Form Saved", "Your new transfer form was successfully saved.");
},
failure: function () {
showModal("btn-danger", "Save Failed", "Your form could not be saved, please contact site support");
}
});
In the controller function, I convert the name value pairs to a list of type 'TransferLineItem', a bound model. I can iterate over the list and use context to save to the database.
dynamic _json = JsonConvert.DeserializeObject<List<TransferLineItem>>(jsonObj);
foreach (TransferLineItem item in _json)
{
try
{
_context.TransferLineItem.Add(item);
int x = await _context.SaveChangesAsync();
if (x != 1)
{
ModalMessage = "Could not save items, starting at " + TransferLineItem.Asset;
return Page();
}
}
catch (Exception ex)
{
ModalType = "btn-danger";
ModalTitle = "Save Failed";
ModalMessage = ex.Message;
return Page();
}
}
I would not do this sort of thing dynamically by modifying the dom in the manner you describe. My preference would be to generate all of the necessary code in the razor view as if it was always there and then simply toggle the visibility of the row itself. This way the textbox is rendered properly as a form element when the view is generated, and you still have full access to modify the table with jQuery pending any AJAX requests.
On a side note, the behavior you're describing makes it sound like you're attempting to add more client side behaviors and reduce the number/size of the round trips to the server. If this is true, I would suggest exploring a JavaScript MVVM framework like Knockout, Ember or Angular.
I am a long time WebForms developer but am finally getting around to learning MVC by converting one of my WebForms sites, which needs updating, to MVC3.
I know the basics of MVC from reading but am struggling in the real world on day one with what are probably simple things, and I would also like to know how best to do them and best practices.
For this answer I’m not looking for code (although a little might help), just enough information to put me on the right path. I have already looked at quite a few examples and tutorials but none seem to show something relevant for my situation, so here I am asking on SO.
So, the first page I am working on is a search results page. It’s a little more complex than a simple search page. It has an area for suggestions if it finds words spelt incorrectly, an area for if no results are found, and an area for the search results themselves, if any.
Because it searches two database tables (views actually) I have a model that contains both table models and a priority field I use for ordering results by most relevant. The model is like this:
public class SearchResult
{
public Table1 { get; set; }
public Table2 { get; set; }
public int Priority { get; set; }
}
In WebForms I use panels to contain each of the areas so I can turn them on and off, something like this:
<asp:Panel ID=”panSuggest” runast=”server” Visible=”false”>
…
</asp:Panel>
<asp:Panel ID=”panNoResults” runat=”server” Visible=”false”>
…
</asp:Panel>
<asp:Panel ID=”panResults” runat=”server”>
<asp:Repeater ID=”repResults” runat=”server”>
…
</asp:Repeater>
</asp:Panel>
In my present WebForms code behind logic I look to see if there are any misspelt works and if so display panSuggest and hide all other panels. If there are no errors then I hide show panResults/panNoResults as necessary.
So how is this kind of thing usually done in MVC? Do I set a ViewBag item in my Controller for whether PanSuggest should be shown which I look for in my View and then choose to hide/show based on that, and check if my Model has any items to determine whether panResults/panNoResults should be shown. Something like my code below or is this not the proper way to do it?
#{ if (ViewBag.Suggest == true) {
<div>
Suggest
</div>
} else {
#{ if (Model.Count == 0) {
<div>
No Results
</div>
} else {
<div>
#foreach (var result in Model) {
#result.Table1.Whatever etc etc
}
</div>
}
}
Update.
I have been reading more and a there is a lot of advice to avoid ViewBag.
So instead should I change my model to include the extra data I need? Something like this
Public class ViewModel
{
public string Suggest { get; set; }
public List<SearchResult> Result { get; set; }
}
public class SearchResult
{
public Table1 { get; set; }
public Table2 { get; set; }
public int Priority { get; set; }
}
Then in my view I can check if ViewModel.Suggest is not empty, and check ViewModel.Result to see if any items (search results) exists.
Is this a better solution?
If I have 2 different tables that needs to be shown, I would to the same, the only thing I would change is
#{
if (ViewBag.Suggest == true)
{
<div>
Suggest
</div>
} else {
<table>
<thead>
<th>Header column</th>
</thead>
<tbody>
#{ if (Model != null && Model.Any()) {
<tr>
#foreach (var result in Model)
{
<td>
#result.Table1.Whatever etc etc
</td>
}
</tr>
} else {
<tr>
<td>
No Results
</td>
</tr>
}
</tbody>
</table>
}
}
My approach would be essentially the same as yours. My rationale is to put all the business logic into the controller, and to pass a simple indicator to the view in the ViewBag that indicates any options for displaying the data. Typically that would be a simple boolean value such as your ViewBag.Suggest value.