Razor skipping nested foreach loops - asp.net-mvc-3

In my database I have a string of child tables. In a razor view I am trying to loop through the ultimate parent and then filter a collection a few levels down.
I have got it to work using the following extract:
#foreach (var artist in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => artist.ArtistName)
</td>
</tr>
foreach (var album in artist.Albums)
{
foreach (var song in album.Songs)
{
if (song.SongPlays != null)
{
foreach (var songPlay in song.SongPlays)
{
<tr>
<td>
#Html.DisplayFor(a => songPlay.PlayTime)
</td>
</tr>
}
}
}
}
}
The issue with this is that I cannot sort the whole child collection by PlayTime. To solve this I then tried to get it working by skipping out the preceding foreach loops using:
foreach (var songPlay in artist.Albums.SelectMany(a => a.Songs.SelectMany(b => b.SongPlays)))
{
<tr>
<td>
#Html.DisplayFor(a => songPlay.PlayTime)
</td>
</tr>
}
This seems to work without the filter applied in the controller action, but returns a null result when the filter is applied. I have tried checking in the view if the result is null, but I could not get this to work - something like:
if (artist.Albums.Select(a => a.Songs.Select(b => b.SongPlays)) != null)
{
foreach (var songPlay in artist.Albums.SelectMany(a => a.Songs.SelectMany(b => b.SongPlays)))
{ ...
I still get a null result, so I am presuming that the null check is not doing what I was hoping it would do.
So if anyone can give me some guidance either on whether this approach is sensible and if I can do a null check on a grandchild collection somehow, or if there would be a better approach, it would be very much appreciated.

I'm not sure I get you right. As far as I understand you need to filter null items and second code sample in your question is ok in terms of orderting. In that case, you may add Where clause to selection:
foreach (var songPlay in artist.Albums.SelectMany(a => a.Songs.Where(b => b != null).SelectMany(b => b.SongPlays)))
{
<tr>
<td>
#Html.DisplayFor(a => songPlay.PlayTime)
</td>
</tr>
}

Related

Reset a table data with an observable as its source

I have an observable that fills a table like this:
<table class="table table-borderless" style="width:44%;" *ngIf="(borrowers_main_data$ | async) as borrowers_main_data">
<tbody>
<tr>
<td width="8%">CDI:</td>
<td>
<strong>{{ borrowers_main_data.Cdi }}</strong>
And this is the code that fills the table:
public borrowers_main_data$ = this.service.cdiVariable$.pipe(
switchMap(cdiVariable => {return this.dataSource.getCustomer(cdiVariable).pipe(
catchError(error => {
if (error.error instanceof ErrorEvent) {
this.errorMsg = `Error: ${error.error.message}`;
} else {
this.errorMsg = `Error: ${error.message}`;
}
return of({} as Customer);
}))
}));
The problem is that in the case of a second search (after a successful one) that returns the Observable of the empty object the table stays populated with the previous data.

Unexpected data \r\n with Carbon laravel

I'm trying to get all of the students from a table using "Student::all()". I don't even have carbon in this function. It's not getting students by date or anything. When i try to run the function, I get the error shown in the picture. It's pointing to a carbon file in the vendor folder but I don't know what to change. The data from the database pulls fine in every other function of the program, just not this one exact thing. When I die/dump my function call,I get the students list just fine. Something is simply irritating Carbon for no apparent reason. If I use a carbon parameter, it works, the function doesn't stall, but it does not return the correct data even though the field in the database holds that info. Why would a line break be causing this issue?
This function does not produce the error, but it does not result in the correct data.
public function exportRoster(){
$students = Student::whereDate('updated_at', Carbon::today())->get();
$pdf = PDF::loadView('printRoster', compact('students'), [], ['orientation' => 'L']);
return $pdf->stream('roster'.Carbon::today().'.pdf');
}
This function would obviously have the right data, but it produces the error of "Unexpected data".
public function exportRoster(){
$students = Student::all();
$pdf = PDF::loadView('printRoster', compact('students'), [], ['orientation' => 'L']);
return $pdf->stream('roster.pdf');
}
Just in case it helps, i've also included a screen shot of my database
Here is the table i'm using with my students variable in the printRoster view. If I remove this table, all queries work.
<table style="width:100%;">
<tr>
<th align = "left">Student Name</th>
<th align = "left">Student ID</th>
<th align = "left">District</th>
<th align = "left">School</th>
<th align = "left">Test Date/Time</th>
<th align = "left">Vision</th>
<th align = "left">Color</th>
<th>Nurse</th>
</tr>
#foreach($students as $student)
#php
$grade = array('20/40', '20/50', '20/60', '20/80', '20/100', '20/200', '20/400');
#endphp
<tr>
<td>{{$student->fname.' '.$student->lname}}</td>
<td>{{$student->student_number}}</td>
<td>{{$student->district}}</td>
<td>{{$student->school}}</td>
<td>{{$student->updated_at}}</td>
#if(in_array($student->od_dist, $grade) || in_array($student->os_dist, $grade) || in_array($student->ou_dist, $grade))
<td>Failed</td>
#else
<td>
Passed
</td>
#endif
<td>{{$student->ou_color}}</td>
<td>{{$student->nurse}}</td>
</tr>
#endforeach
</table>
The updated_at column is a timestamp so maybe you need to convert it in a raw date in order to show it. Please try if it works
#foreach($students as $student)
#php
$grade = array('20/40', '20/50', '20/60', '20/80', '20/100', '20/200', '20/400');
#endphp
<tr>
<td>{{$student->fname.' '.$student->lname}}</td>
<td>{{$student->student_number}}</td>
<td>{{$student->district}}</td>
<td>{{$student->school}}</td>
<td>{{date('Y-m-d H:i:s', strtotime($student->updated_at))}}</td>
#if(in_array($student->od_dist, $grade) || in_array($student->os_dist, $grade) || in_array($student->ou_dist, $grade))
<td>Failed</td>
#else
<td>
Passed
</td>
#endif
<td>{{$student->ou_color}}</td>
<td>{{$student->nurse}}</td>
</tr>
#endforeach
Edit
public function exportRoster(){
$students = Student::all();
$pdf = PDF::loadView('printRoster', $students);
$pdf->setPaper('A4', 'landscape');
return $pdf->stream('roster.pdf');
}

MVC and Razor to display integer when value is empty or 0

I have the following code in the View.
<span>#Html.DisplayFor(modelItem => item.comments.comments_id)</span>
<span>#item.comments.comments_id</span>
The code below works if comments_id is not 0 or empty.
<span>#((item.comments.comments_id == 0) ? 0 : #item.comments.comments_id)</span>
If its 0 or empty I get
System.NullReferenceException: Object reference not set to an instance of an object.
The class contains this
public Nullable<int> comments_id { get; set; }
How can overcome this issue? thanks in advance.
---- EDit more code ---
public ActionResult Show()
{
var showItems = db.Projects.Include(p => p.Comments).ToList(); // INCLUDES ITEMS FROM BOTH TABLES
return View(showItems);
}
View
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.ProjectName)
</td>
<td>
#Html.DisplayFor(modelItem => item.Comments.comments_id) // NOTICE this coming from a different table(Comments tbl).
</td>
<td>
<span>#((item.Comments.comments_id == 0) ? 0 : #item.Comments.comments_id) // HERE when item.Comments.comments_id has no contents it throws an error.
Create
</td>
</tr>
}
Someone posted something similar but I don't understand the answer.
http://forums.asp.net/t/1732717.aspx?How+to+check+if+model+property+is+empty+in+View+page
You need to use HasValue to check if a nullable variable has a value or not.
<span>#((item.comments.comments_id.HasValue) ? #item.comments.comments_id : 0)</span>
EDIT: Added Example
Your view code looks like it should work. Below is code I wrote to test your view. The lambda expression in your controller action won't be executed until it's used. So it's possible it's not executed until the view is rendered. This could cause a problem because the database connection may be closed by then. However, the call to ToList() should execute the lambda expression. So the problem is probably that item.Comments is null. You should test to see if it is as I did in my example.
Controller
public class HomeController : Controller
{
public class Project
{
public string ProjectName { get; set; }
public ProjectComments Comments { get; set; }
}
public class ProjectComments
{
public string Comments { get; set; }
public Nullable<int> comments_id { get; set; }
}
public ActionResult Index()
{
var showItems = new List<Project>();
showItems.Add(new Project()
{
ProjectName = "Project 1",
Comments = new ProjectComments() { Comments = "some comments", comments_id = 1 }
});
showItems.Add(new Project()
{
ProjectName = "Project 2",
Comments = new ProjectComments() { Comments = "more comments", comments_id = null }
});
return View(showItems);
}
}
View
#model IList<MvcApplication2.Controllers.HomeController.Project>
<table border="1">
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.ProjectName)
</td>
<td>
#Html.DisplayFor(modelItem => item.Comments.comments_id)
</td>
<td>
<span>
#((item.Comments != null && item.Comments.comments_id.HasValue) ? #item.Comments.comments_id : 0)
Create
</span>
</td>
</tr>
}
</table>

Null entity when using .find method in entity framework

I have been trying to create a simple portal to track logs from a mobile application. As such, I have used entity framework and MVC3 to help me with this. However recently I have been stuck when trying to retrieve the entity from the database.
Here is the Run class:
namespace LifestyleGuide.Models
{
[DataContract(IsReference = true)]
[KnownType(typeof(User))]
public partial class Run
{
[DataMember]
public string User_ID { get; set; }
[DataMember]
public System.DateTime Date { get; set; }
[DataMember]
public Nullable<int> Distance { get; set; }
[DataMember]
public Nullable<int> Duration { get; set; }
[DataMember]
public Nullable<int> Calories { get; set; }
[DataMember]
public virtual User User { get; set; }
}
}
User_ID and date are form a composite key where User_ID is a foreign key from the User table.
And the following is the "details" method from the controller:
public ActionResult Details(String id, DateTime date)
{
using (var db = new inspireEntities())
{
Run run = db.Runs.Find(id, date);
return View(run);
}
}
However, when i try to run it, the run object always appears as a null.
Any suggestions are greatly appreciated!
EDIT:
Here are is the view for the homepage.
#model IEnumerable<LifestyleGuide.Models.Run>
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<p>
#Html.ActionLink("Create New", "Create")
</p>
<table>
<tr>
<th>
<center>User ID</center>
</th>
<th>
<center>Date</center>
</th>
<th>
<center>Distance</center>
</th>
<th>
<center>Duration</center>
</th>
<th>
<center>Calories</center>
</th>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.User_ID)
</td>
<td>
#Html.DisplayFor(modelItem => item.Date)
</td>
<td>
#Html.DisplayFor(modelItem => item.Distance)
</td>
<td>
#Html.DisplayFor(modelItem => item.Duration)
</td>
<td>
#Html.DisplayFor(modelItem => item.Calories)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id = item.User_ID, date = item.Date }) |
#Html.ActionLink("Details", "Details", new { id = item.User_ID, date = item.Date }) |
#Html.ActionLink("Delete", "Delete", new { id = item.User_ID, date = item.Date })
</td>
</tr>
}
</table>
The fields in the table are populated from the database directly and therefore should already exist.
Note: I have no problems with creating and accessing the run objects by using the view. The null run object only occurs when I directly do an insert statement into the database and when i try to retrieve it afterwards using the .find method as shown above.
Find() function returns first occurrence of matching item from the Collection which will be a single item that matched the condition. Since your view is strongly typed to IEnumerable<LifestyleGuide.Models.Run>, it's expecting a collection of Run objects not a single object.
You should modify your controller so that a collection (list) of Run objects are passed to the view. You could use WHERE clause like this :
public ActionResult Details(String id, DateTime date)
{
using (var db = new inspireEntities())
{
List<Run> run = db.Runs.Where(r=>r.Id==id && r=>r.Date==date);
return View(run);
}
}
Good luck :).
I realized the problem! Each entry to the database has a DateTime object with milliseconds while the query doesn't. I did a work-around to remove the milliseconds from all entries and it works!

Asp.Net MVC 3 - Persist a List through different Views

i'm new at this tecnology and i'm having some trouble passing a list of an excel that i imported to my application, here's the code:
The problems is that the model in the Create Controller comes out null so i cant save into the database.
I can't save it before, in the uploadcomplete action because i intend to edit the values before save into the data base.
[HttpPost]
public ActionResult Index(HttpPostedFileBase excelFile)
{
if (excelFile != null)
{
//Save the uploaded file to the disc.
string savedFileName = Server.MapPath("~/UploadedExcelDocuments/" + excelFile.FileName);
excelFileHandler.ImportExcel(savedFileName, excelFile);
return RedirecToAction("UploadComplete",excelFileHandler.DataToEdit);
}
else { return RedirectToAction("Error", "Upload"); }
}
public ActionResult UploadComplete(List<Persona> DataToEdit) // This comes out null so i cant render the view now
{
return View();
}
[HttpPost]
public ActionResult UploadComplete(IEnumerable<ExcelImport.Persona> model)
{
return View();
}
public ActionResult Create(IEnumerable<ExcelImport.Models.Person> model)
{
using (ExcelimportDBTestEntities context = new ExcelimportDBTestEntities())
{
foreach (ExcelImport.Models.Person person in model)
{
Persona newPerson = new Person();
newPersona.Id = person.Id;
newPersona.Birthday= persona.Birthday;
newPersona.LastName= persona.LastName;
newPersona.Name = persona.Name;
context.Persons.AddObject(newPersona);
context.SaveChanges();
}
return View();
}
}
This is my View, there must be something wrong here
#model IEnumerable<ExcelImport.Models.Person>
#{
ViewBag.Title = "UploadComplete";
}
<h2>UploadComplete</h2>
#Html.BeginForm(){
<table>
<tr>
<th>
ID
</th>
<th>
Name
</th>
<th>
Last Name
</th>
<th>
Birthday
</th>
<th>
Options
</th>
</tr>
#foreach (var item in Model) {
#Html.HiddenFor(model => item)
<tr>
<td>
#Html.DisplayFor(modelItem => item.Id)
</td>
<td>
#Html.DisplayFor(modelItem => item.Name)
</td>
<td>
#Html.DisplayFor(modelItem => item.LastName)
</td>
<td>
#Html.DisplayFor(modelItem => item.Birthday)
</td>
<td>
</td>
</tr>
}
</table>
<input type="submit" value="Upload!"/>
}
EDIT: i was tired yesterday so i put some... lets go whit "test" that i was doing by error, now this is what i really want to do. I got an Index View that upload the file and send to the post Index Controller, from there i want to send the list to my UploadComplete Controller, so i can render the UploadComplete View (the list comes out null), and in the post of that Action i want to send the model that i render in the UploadComplete View, to my create controller, so i can storage my data into the database. And as i said before i cant save it into the datebase in the index action becouse i intend to edit this data in the uploadcomplete view.
Thanks in advance, Regards.
As I can see in your code:
There is no [HttpPost] attribute
Form action is GET
Incorrect page rendering (hidden elemens)
Look at this example. It shows how lists could be binded on POST.

Resources