ASP.Net Razor View - asp.net

I may be doing it wrong... so please correct me if i am.
I've pulled my Last.FM data from their RestAPI and cached it (to be refreshed only if the cache is greater than 30 minutes old), and from there i've loaded it into an enumerated list of tracks.
I'm attempting to drop that logic in the Razor display, and never managed to make it work with more than just the foreach and if (item.image...)..., adding in the logic to drop the divs has caused razor to loose track of the closing bracket for the foreach.
Am I making this too complicated?
<!-- lfm data -->
#* Iterate over the Last.FM data and display it in an attractive format *#
#foreach (var group in Model.Select((x, i) => new { Group = i / 4, Item = x })
.GroupBy(x => x.Group)) {
<div class="LFM-Data">
foreach(var x in group) {
if (x.item.image != null) {
<img src="#x.item.image.ToString()" class="lfm-artwork" alt="#x.item.album"/>
} else {
<img src="/Content/images/lfm/NoAlbumArt.jpg" class="lfm-artwork" alt="No Album Art Available" />
}
<p>#Html.Raw(x.item.name.ToString())</p>
}
</div>
}
after following Equiso's suggestion, i'm getting an odd scoping issue where either X is not in the current scope, or x does not contain a property for image...
#model IEnumerable<CCBlog.Classes.LastFmWrapper.Track>
and this is part of the LFM Wrapper class --- that i'm modeling the data after
public struct Track
{
public string artist { get; set; }
public string name { get; set; }
public string album { get; set; }
public string image { get; set; }
}
I call shenanigans!

If you are trying to display the items in groups of 4 you could do somethig like this
#foreach (var group in Model.Select((x, i) => new { Group = i / 4, Item = x })
.GroupBy(x => x.Group)) {
<div class="LFM-Data">
foreach(var x in group) {
if (x.Item.image != null) {
<img src="#x.Item.image.ToString()" class="lfm-artwork" alt="#x.Item.album"/>
} else {
<img src="/Content/images/lfm/NoAlbumArt.jpg" class="lfm-artwork" alt="No Album Art Available" />
}
<p>#Html.Raw(x.Item.name.ToString())</p>
}
</div>
}
or you could create a ViewModel that get the items grouped already.

Related

Blazor InputText with Required attribute but Disabled

So I have a model, other properties removed for brevity:
public class OutOfLimitReasonViewModel
{
[Required]
public int ReasonId { get; set; }
[Required(ErrorMessage = "Other Reason is required")]
public string OtherReason { get; set; }
}
Of course I have an EditForm on the .razor page and the InputText I care about looks like this:
<InputText #bind-Value="model.OtherReason" class="form-control" disabled="#(!OtherReasonRequired)" />
<ValidationMessage For="#(() => model.OtherReason)" />
There is also a select that has the list of available Reason objects, one of which is Other.
I do have a property called OtherReasonRequired which graphically does what I want (either Enable or Disable the input based on if the selected Reason == "Other") so that code works:
public bool OtherReasonRequired
{
get
{
var result = false;
if (model.ReasonId > 0)
{
var reason = Reasons.Find(x => x.Id == model.ReasonId);
result = reason.Reason == "Other";
}
return result;
}
}
This works perfectly if I select Other and give OtherReason a value, the Save/Submit button is valid and it works.
My issue is when I have NOT selected Other. Graphically, the InputField does get disabled and grayed out. But the Save/Submit believes the model is invalid because there is no value in the OtherReason field.
Is there something I can do to get this to work?
Would love to have a dynamic attribute called RequiredIf.
But logically to me, I see this as a bug. If a control is disabled, it's value is irrelevant in my mind.
Please check the following. I don't use any of the built-in Data Annotation, but it's still very easy to check the input and let the user know what I want them to do:
<EditForm Model="#DisplayModel" OnValidSubmit="HandleValidSubmit" >
<InputRadioGroup TValue=int? #bind-Value=DisplayModel.ReasonID>
#for (int i=1; i< Reasons.Count(); i++){
<InputRadio Value=Reasons[i].ID /> #Reasons[i].Description <br/>
}
<InputRadio Value=0 />Other <br/>
</InputRadioGroup>
<input #bind=DisplayModel.OtherText disabled=#((DisplayModel.ReasonID??1) !=0 ) />
<button type="submit">Submit</button>
<div class="text-danger">#DisplayMessage</div>
</EditForm>
#code {
string DisplayMessage="";
class Reason { public int? ID; public string? Description; }
List<Reason> Reasons = new List<Reason> {
new Reason { ID = 0, Description = "Other"},
new Reason { ID = 1, Description = "You're lame" },
new Reason { ID = 2, Description = "I'm too busy" }
};
class MyDisplayModel
{
public int? ReasonID;
public string OtherText="";
}
MyDisplayModel DisplayModel = new MyDisplayModel();
private async Task HandleValidSubmit()
{
if(DisplayModel.ReasonID is not null) if (DisplayModel.ReasonID==0) if (DisplayModel.OtherText == "")
{
DisplayMessage = "You must type a description of your issue.";
StateHasChanged();
await Task.Delay(1500);
DisplayMessage = "";
}
}
}

MVC 5: Controller, Database and View have strange behaviour

So I have this little "Restaurant" webapp going on where I'm trying to construct a View-page where an user can click on a created (restaurant) table (dropdown that refreshes automatically after clicking) and check what dishes are ordered on that table. At the bottom, the user will find the total price.
My view works 100% fine but ONLY if I have 1 table in the database. If I have multiple tables (restaurant tables) (created in my DropCreate-Seed method), the view will only show the dropdown with available tables, not the dishes inside of them.
What could cause this problem?
CODE
TABLE
public class Table
{
[Required]
public int Id { get; set; }
[Required]
public string Name { get; set; }
public virtual List<Dish> Dishes { get; set; }
}
SEED METHOD
context.Tables.Add(new Table { Id = 1 ,Name = "table1", Dishes = context.Dishes.ToList() });
context.Tables.Add(new Table { Id = 2, Name = "table2", Dishes = context.Dishes.ToList() });
context.Tables.Add(new Table { Id = 3, Name = "table3", Dishes = context.Dishes.ToList() });
context.SaveChanges();
TABLE CONTROLLER
public ActionResult Order(int? tableID)
{
//Create a ViewBag variable contained with all the tables (show name)
List<table> tableL = db.tables.ToList();
List<SelectListItem> tableSL = new List<SelectListItem>();
foreach (var table in tableL)
{
TableSL.Add(new SelectListItem { Text = table.Name.ToLower(), Value = table.Name.ToString() });
}
ViewBag.tableL = tableSL;
//At the start or at problems, get the first table and return it
if (tableID == null || db.tables.Find(tableID) == null)
{
return View(db.tables.First());
}
else
{
Table l = db.tables.Find(tableID);
return View(l);
}
}
VIEW
#model VBExamenTEST.Models.Table
#{
ViewBag.Title = "Order";
}
<h2>Order</h2>
#using (Html.BeginForm("Bedien", "Bedien", FormMethod.Post))
{
#Html.DropDownList("tableID", (List<SelectListItem>)ViewBag.TableL, new {onchange = "this.form.submit()" });
}
#if(Model != null)
{
double total = 0;
<table>
<tr>
#foreach(var g in Model.Dishes)
{
total += g.Price;
<td>
#Html.DisplayFor(Model=>g.Name)
</td>
}
</tr>
</table>
<p>Total:#total euro </p>
}
So my code works perfectly if I only have one table added in my DB, whenever I add more, only the dropdown shows up, the dishes are not shown on click, and the total equals 0.
Where can my problem be situated?

How to Display multiple images from db using MVC3

I am new to MVC.I have saved the image and some data but can't display the saved images. I want to display all saved images in the main page.
Model: Get the db list from model
public List<Products> GenreList()
{
}
Controller
public ActionResult MYsample()
{
var MyList = storeDB.GenreList();
var a= MyList.Count;
if (a != null)
{
foreach (var li in MyList)
{
return File(li.fileContent, li.mimeType,li.fileName);
}
}
return View(MyList);
}
View
#foreach (var item in Model)
{
<img src="#Url.Action("MYsample", "HomeController", new { id = item.ProductID })" alt="#item.Productname" />
}
You could start by writing a controller action that will serve the images to the response stream:
public ActionResult Image(int id)
{
// you should add a method to your repository that returns the image
// record from the id
Products image = storeDB.Get(id);
return File(image.fileContent, image.mimeType);
}
and then in your main controller action send the list of images to the view:
public ActionResult MySample()
{
var model = storeDB.GenreList();
return View(model);
}
and then in your strongly typed view loop through the images and generate an <img> tag for each image by pointing its src property to the newly created controller action:
#model MyList
#foreach (var li in MyList)
{
<img src="#Url.Action("Image", new { id = li.Id })" alt="" />
}
If you don't want to have a separate controller action that will query the database and retrieve the image record from an id you could use the data URI scheme. Bear in mind though that this is not supported by all browsers.
So the idea is that your controller action will send the image data to the view:
public ActionResult MySample()
{
var model = storeDB.GenreList();
return View(model);
}
and then inside your strongly typed view you could loop through the list and generate the proper <img> tag:
#model MyList
#foreach (var li in MyList)
{
<img src="src="data:#(li.mimeType);base64,#(Html.Raw(Convert.ToBase64String(li.fileContent)))" alt="" />
}

Display uploaded images

I'm trying to create a simple image gallery. Uploading works, but I have problems with displaying those images.
In the internet I found that this is the right way to do it:
[NotMapped]
public string ImageUrl
{
get
{
var isEmpty = String.IsNullOrWhiteSpace(ImgName);
if(isEmpty)
{
return Path.Combine("~/Images", "noImageAvailable.png");
}else
{
return Path.Combine("~/Images/uploaded", ImgName);
}
}
}
and in the view
#foreach (var item in Model) {
...
#{ var imgPath = HostingEnvironment.MapPath(item.ImageUrl); }
<img src="#Url.Content(imgPath)"/>
Which produces:
<img src="C:\......\Images\uploaded\0_634927659072110613.jpg"/>
What worked for me is:
[NotMapped]
public string ImageUrl
{
get
{
var isEmpty = String.IsNullOrWhiteSpace(ImgName);
if(isEmpty)
{
return Path.Combine("../Images", "noImageAvailable.png");
}else
{
return Path.Combine("../Images/uploaded", ImgName);
}
}
}
and in the view:
#foreach (var item in Model) {
.....
<img src="#Url.Content(item.ImageUrl)"/>
Which produces:
<img src="../Images/uploaded\0_634927649098750170.jpg"/>
Remarks
There are 2 differences:
~/Images vs ../Images
the lines in the view
What is interesting is that the line
<img src="C:\......\Images\uploaded\0_634927659072110613.jpg"/>
displays an image in a static standalone file, while when it's served by the IIS it doesn't. There is just blank space instead of an image.
My question is what is the right approach, and also why does't the first one work?
Your code is doing exactly what you're asking. The 1st one doesn't work because var imgPath = HostingEnvironment.MapPath(item.ImageUrl); returns a physical path on the server to the image URL, NOT a URL. Use the 1st block with <img src="#Url.Content(item.ImageUrl)"/>. This looks like:
[NotMapped]
public string ImageUrl
{
get
{
var isEmpty = String.IsNullOrWhiteSpace(ImgName);
if(isEmpty)
{
return Path.Combine("~/Images", "noImageAvailable.png");
}else
{
return Path.Combine("~/Images/uploaded", ImgName);
}
}
}
with your view:
#foreach (var item in Model) {
.....
<img src="#Url.Content(item.ImageUrl)"/>
"~/Images/..." in .net says from web root, find the folder Images,
then ...
"../Images/..." is relative to the current location - go up
one folder, find folder images, then ...

ASP.Net MVC 3 ListBox Selected Items Collection Null

I have a pretty simple scenario and I'm sure I'm just missing something obvious. I'm trying to use a ListBox to grab multiple Id's and add them to my model, but no matter what I do, the collection is always null. Here's the code:
The model collections:
public IEnumerable<Model.UserProfile> TravelBuddies { get; set; }
public IEnumerable<int> SelectedTravelBuddies { get; set; }
I populate the TravelBuddies collection in my controller.
The view code:
<div class="module_content">
#if (Model.TravelBuddies.Count() > 0)
{
#Html.ListBoxFor(m => m.SelectedTravelBuddies, new MultiSelectList(Model.TravelBuddies, "Id", "FullName"))
}
else
{
<span>You don't currently have any travel buddies (people who were with you on this trip). Don't worry, you can add some to this trip later if you'd like.</span>
}
</div>
The select list is populated in my view. No problem there. But once I select multiple items and submit my form, the Model.SelectedTravelBuddies collection is always null. Am I missing something obvious? It's been a long night of coding.
Update: Added Controller Code
[HttpGet]
public ActionResult New()
{
Model.Trip trip = new Model.Trip();
ITripService tripService = _container.Resolve<ITripService>();
IUserAccountService userService = _container.Resolve<IUserAccountService>();
int userProfileId = userService.GetUserProfile((Guid)Membership.GetUser().ProviderUserKey).Id;
trip.TripTypes = new SelectList(tripService.GetTripTypes(), "Id", "Name");
trip.TravelBuddies = userService.GetTravelBuddies(userProfileId);
tripService.KillFlightLegTempStorage();
return View(trip);
}
[HttpPost]
public ActionResult New([Bind(Exclude = "TripTypes")] Model.Trip trip)
{
ITripService tripService = _container.Resolve<ITripService>();
if (!ModelState.IsValid)
{
tripService.KillFlightLegTempStorage();
return View(trip);
}
int tripId = tripService.CreateTrip(trip, (Guid)Membership.GetUser().ProviderUserKey);
tripService.KillFlightLegTempStorage();
return RedirectToAction("Details", "Trip", new { id = tripId });
}
Ok so you are binding to SelectedTravelBuddies. When your list is rendered, what is it's name? It's been a long night for me too :) want to make sure it matches the model. Also are you sure the list is in the form element so they are posted?

Resources