I am developing an application where the administrator types a Datetime as searching terms to match stamp dates in the database.
I need to change it so the search criteria can be based on year and week number. The scenario is the user enter year and week number in the GetWeekStamp View, which after they post redirects to Stampings view where they display the data based on the entered year and week number.
Model 1:
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace Aviato.Models
{
public partial class Stamping
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[Required]
public int UserId { get; set; }
[Required]
[DataType(DataType.DateTime)]
public DateTime Timestamp { get; set; }
[Required]
[StringLength(3)]
public string StampingType { get; set; }
public virtual User User { get; set; }
}
}
Model 2:
using System;
using System.Collections.Generic;
using Aviato.Models;
namespace Aviato.ViewModel
{
public class StampingModel
{
public List<Stamping> Stampings { get; set; }
public DateTime Timestamp { get; set; }
}
}
View (GetWeekStamp):
#model Aviato.Models.Stamping
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<h1>Ange Datum</h1>
<p>(ÅÅÅÅ-MM--DD)</p>
#Html.EditorFor(model => model.Timestamp, new { htmlAttributes = new { #class = "form-control" } })
<br/>
<br />
<input type="submit" value="Välj" class="btn btn-default">
<br />
<br />
<div>
#Html.ActionLink("Tillbaka", "Index")
</div>
}
View(Stampings)
#model Aviato.ViewModel.StampingModel
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<h2>Instämplingar</h2>
<p>Du har valt: #Model.Timestamp.Year-#Model.Timestamp.Month-#Model.Timestamp.Day</p>
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.Stampings[0].Timestamp)
</th>
<th>
#Html.DisplayNameFor(model => model.Stampings[0].StampingType)
</th>
</tr>
#foreach (var item in Model.Stampings)
{
<tr>
<td>
#Html.DisplayFor(model => item.Timestamp)
</td>
<td>
#Html.DisplayFor(model => item.StampingType)
</td>
</tr>
}
</table>
<p>
#Html.ActionLink("Tillbaka", "GetWeekStamp")
</p>
}
Controller:
public ActionResult GetWeekStamp()
{
return View();
}
[HttpPost]
public ActionResult GetWeekStamp(Stamping model)
{
return RedirectToAction("Stampings", new { model.Timestamp });
}
public ActionResult Stampings(Stamping model)
{
var startTime = model.Timestamp;
var endTime = model.Timestamp.AddDays(1);
var userId = (int)Session["userId"];
var stampings = _db.Stampings.Where(s => s.Timestamp >= startTime && s.Timestamp <= endTime)
.Where(s => s.UserId == userId).ToList();
var stampingModel = new StampingModel();
stampingModel.Stampings = stampings;
stampingModel.Timestamp = model.Timestamp;
return View(stampingModel);
}
I have found this Converter class here in Stack, but I am not sure what to do with it...
Class:
public class DateConverter
{
public static DateTime FirstDateOfWeek(int year, int weekOfYear)
{
var jan1 = new DateTime(year, 1, 1);
var daysOffset = DayOfWeek.Thursday - jan1.DayOfWeek;
var firstThursday = jan1.AddDays(daysOffset);
var cal = CultureInfo.CurrentCulture.Calendar;
var firstWeek = cal.GetWeekOfYear(firstThursday, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);
var weekNum = weekOfYear;
if (firstWeek <= 1)
{
weekNum -= 1;
}
var result = firstThursday.AddDays(weekNum * 7);
return result.AddDays(-3);
}
}
you can get week number using extension method like this:
public static int GetWeekNumber(this DateTime dateTime)
{
CultureInfo currentCulture = CultureInfo.CurrentCulture;
return currentCulture.Calendar.GetWeekOfYear(dateTime, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);
}
to get a year from DateTime just use:
var datetime = DateTime.Now; //i'm using Now, but you can use the one from Timestamp ...
var year = datetime.Year;
You need to create a model for GetWeekStamp view
using System;
using System.Collections.Generic;
using Aviato.Models;
namespace Aviato.ViewModel
{
public class GetWeekStampModel
{
public int Year { get; set; }
public int WeekNo { get; set; }
}
}
then change GetWeekStamp view code to this so user can enter the year and week number
#model Aviato.ViewModel.GetWeekStampModel
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<h1>Year</h1>
#Html.EditorFor(model => model.Year, new { htmlAttributes = new { #class = "form-control" } })
<br />
<br />
<h1>Week No</h1>
#Html.EditorFor(model => model.WeekNo, new { htmlAttributes = new { #class = "form-control" } })
<br />
<br />
<input type="submit" value="Välj" class="btn btn-default">
<br />
<br />
<div>
#Html.ActionLink("Tillbaka", "Index")
</div>
}
then in GetWeekStamp controller post action method, pass the entered year and week number to Stampings view
[HttpPost]
public ActionResult GetWeekStamp(GetWeekStampModel model)
{
return RedirectToAction("Stampings", new { year = model.Year, weekNo = model.WeekNo });
}
The Timestamp property in StampingModel class should be removed and two new properties Year and WeekNo should be added
using System;
using System.Collections.Generic;
using Aviato.Models;
namespace Aviato.ViewModel
{
public class StampingModel
{
public List<Stamping> Stampings { get; set; }
public int Year { get; set; }
public int WeekNo { get; set; }
}
}
in Stampings controller get action method you can calculate the first date of the week based on year and weekNo using your FirstDateOfWeek method above, then use the results as the startTime and set endTime to six days after startTime
public ActionResult Stampings(int year, int weekNo)
{
var startTime = DateConverter.FirstDateOfWeek(year, weekNo);
var endTime = startTime.AddDays(6);
var userId = (int)Session["userId"];
var stampings = _db.Stampings.Where(s => s.Timestamp >= startTime && s.Timestamp <= endTime)
.Where(s => s.UserId == userId).ToList();
var stampingModel = new StampingModel();
stampingModel.Stampings = stampings;
stampingModel.Year = year;
stampingModel.WeekNo = weekNo;
return View(stampingModel);
}
Finally change this part in Stampings view
<p>Du har valt: #Model.Timestamp.Year-#Model.Timestamp.Month-#Model.Timestamp.Day</p>
to this
<p>Du har valt: #Model.Year-#Model.WeekNo</p>
Related
In my project, I have Cinema, Movie, and Screening Models. Now I want that a user would be able to order tickets for a screening of his choice, according to his chosen cinema. First, the user will select a cinema, then he will see the screenings that are available for the cinema he chose.
Using a foreach method I'm iterating over the screenings available in the chosen cinema and display them inside forms, so the user can click the "Order Now" button to submit the form for the specific screening he chose.
Here you can see my view:
#model IEnumerable<CinemaProjectMVC.Models.Screening>
#{
ViewBag.Title = "OrderForm";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Buy Tickets</h2>
<table id="screenings" class="table table-bordered table-hover">
<thead>
<tr>
<th>Movie</th>
<th>Date</th>
<th>Tickets</th>
<th>Price</th>
<th>Order Now!</th>
</tr>
</thead>
<tbody>
#{
if (!Model.Any())
{
<tr>
<td class="empty-table" colspan="5">There are no screenings.</td>
</tr>
}
}
#foreach (var screening in Model)
{
using (Html.BeginForm("Save", "Orders"))
{
#Html.ValidationSummary(true, "Please fix the following errors.")
<tr>
<td>#screening.Movie.Name</td>
<td>#screening.Date.ToString("d MMM yyyy, HH:mm")</td>
<td>
#Html.TextBoxFor(s => screening, new { #type = "number", Value = "1" })
#Html.ValidationMessageFor(s => screening)
</td>
<td id="#screening.Price">#screening.Price</td>
<td><button type="submit" class="order-now-button">Order Now</button></td>
</tr>
#Html.HiddenFor(s => s.Id)
#Html.AntiForgeryToken()
}
}
</tbody>
</table>
Now, there is an issue with the line #Html.HiddenFor(s => s.Id), probably because I'm using an IEnumerable as a Model. Without passing the Id in the form I can't pass it to another action.
I tried changing this line to #Html.HiddenFor(s => screening.Id) which compiles, but still i'm not getting the data I need in the "Save" action.
My Action:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Save(Screening screening)
{
return RedirectToAction("", "");
}
Right now my action is empty, but through debugging I can see the "screening" variable is null after I submit the form.
This is the action that passes the data about screenings to the form in the OrderForm view:
public ActionResult AvailableScreenings(int id)
{
var screenings = _context.Screenings.Where(s => s.CinemaId == id).ToList();
var cinemas = _context.Cinemas.ToList();
var movies = _context.Movies.ToList();
var viewModel = new ScreeningFormViewModel
{
Cinemas = cinemas,
Movies = movies,
Date = DateTime.Now
};
return View("OrderForm", screenings);
}
And finally, I will add my Screening and ScreeningFormViewModel Models just in case -
Screening Model:
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web;
namespace CinemaProjectMVC.Models
{
public class Screening
{
public int Id { get; set; }
public Cinema Cinema { get; set; }
[Required]
public byte CinemaId { get; set; }
public Movie Movie { get; set; }
[Required]
public byte MovieId { get; set; }
[Required]
public DateTime Date { get; set; }
[Required]
[Display(Name = "Available Seats")]
[ValidNumberOfSeats]
public int AvailableSeats { get; set; }
[Required]
[Range(0, int.MaxValue, ErrorMessage = "Please enter valid number")]
public int Price { get; set; }
public Screening() { }
public Screening(int id, Cinema cinema, Movie movie, byte cinemaId, byte movieId, DateTime date, int availableSeats, int price)
{
Id = id;
Cinema = cinema;
Movie = movie;
CinemaId = cinemaId;
MovieId = movieId;
Date = date;
AvailableSeats = availableSeats;
Price = price;
}
}
}
ScreeningFormViewModel:
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using CinemaProjectMVC.Models;
using System.Linq;
using System.Web;
namespace CinemaProjectMVC.ViewModels
{
public class ScreeningFormViewModel
{
public int? Id { get; set; }
public IEnumerable<Cinema> Cinemas { get; set; }
[Required]
[Display(Name = "Cinemas")]
public byte? CinemaId { get; set; }
public IEnumerable<Movie> Movies { get; set; }
[Required]
[Display(Name = "Movies")]
public byte? MovieId { get; set; }
[Required]
public DateTime Date { get; set; }
[Required]
[Display(Name = "Available Seats")]
public int AvailableSeats { get; set; }
[Required]
[Range(0, int.MaxValue, ErrorMessage = "Please enter valid number")]
public int Price { get; set; }
public string Title
{
get
{
return Id != 0 ? "Edit Screening" : "New Screening";
}
}
public ScreeningFormViewModel()
{
Id = 0;
}
public ScreeningFormViewModel(Screening screening)
{
Id = screening.Id;
CinemaId = screening.CinemaId;
MovieId = screening.MovieId;
Date = screening.Date;
AvailableSeats = screening.AvailableSeats;
Price = screening.Price;
}
}
}
I'm not sure where my problem is, maybe I'm not passing the right Model to the view, or maybe there are other issues in my form.
You can do so by modifying your view code as:
#for(int i=0;i<Model.Count;i++)
{
using (Html.BeginForm("Save", "Orders"))
{
#Html.ValidationSummary(true, "Please fix the following errors.")
<tr>
<td>#Html.DisplayFor(m=>m[i].Movie.Name</td>
<td>#Html.DisplayFor(m=>m[i].Date.ToString("d MMM yyyy, HH:mm"))</td>
<td>
#Html.TextBoxFor(m =>m[i].screening, new { #type = "number", Value = "1" })
#Html.ValidationMessageFor(m =>m[i].screening)
</td>
<td>m=>m[i].Price</td>
<td><button type="submit" class="order-now-button">Order Now</button></td>
</tr>
#Html.HiddenFor(m => m[i].Id)
#Html.AntiForgeryToken()
}
}
Using this you can easily achieve what you actually wanted with the iterative form or we can say order based form.
Let me know if this answer is useful to you.
Friends, I have implemented a solution type ASP.NetCore with a project MVC. I have a view in which I used https://github.com/cloudscribe/cloudscribe.Web.Pagination for pagination. **Honestly I took the example and used it. But I don't get the detail about this code example.
The problem that I have now is that, I have to include filters, like datepicker range. So I am using bootstrap datepicker. But the pagination stopped working.
The pagination gets this parameters in querytrings to work: pageNumber, pageSize and query. When I send the request of the filter date, I can get the dates selected in the controller, but the parameters of pagination get in null.
This is an URL example with pagination working fine: http://localhost/pager?query=1&pagesize=10&pageNumber=2
This is an URL when I send the request in the button 'Apply' with dates range, and pagination died without its parameters like 'query': http://localhost/pager?startDate=11/04/2019&endDate=11/11/2019
I suppose I have to send the current querystring in the request too, but I'm not sure, I'm kind of new at this technology. Thanks for any help.
My view →
#using (Html.BeginForm("Details", "Movements", routeValues: new { pageNumber = #Model.UserMovementsResults.PageNumber, pageSize = #Model.UserMovementsResults.PageSize, query = #Model.Query }, FormMethod.Get))
{
<br />
<div style="border: 2px solid #dee2e6;padding: 5px;width: 50%;">
<br />
<div class="input-daterange input-group" id="datepicker">
<span style="font-weight:bold">Date</span> From
#Html.TextBoxFor(model => model.StartDateFilter, "{0:d MMM yyyy}", new
{
id = "StartDateFilter",
#class = "input-sm form-control",
#readonly = "readonly"
})
<span class="input-group-addon"> To </span>
#Html.TextBoxFor(model => model.EndDateFilter, "{0:d MMM yyyy}", new
{
id = "EndDateFilter",
#class = "input-sm form-control",
#readonly = "readonly"
})
</div>
<br />
<input type="submit" value="Apply" class="btn btn-primary" name="Apply" />
</div>
<br />
<br />
<table class="table table-striped table-bordered">
<thead>
<tr>
<th>
#Html.DisplayNameFor(model => model.UserMovementsResults.Data.FirstOrDefault().Date)
</th>
<th>
#Html.DisplayNameFor(model => model.UserMovementsResults.Data.FirstOrDefault().Description)
</th>
</tr>
</thead>
<tbody>
#foreach (var item in Model.UserMovementsResults.Data)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.Date)
</td>
<td>
#Html.DisplayFor(modelItem => item.Description)
</td>
</tr>
}
</tbody>
</table>
<div>
<cs-pager cs-paging-pagesize="#Model.UserMovementsResults.PageSize"
cs-paging-pagenumber="#Model.UserMovementsResults.PageNumber"
cs-paging-totalitems="#Model.UserMovementsResults.TotalItems"
cs-pagenumber-param="pageNumber"
cs-show-first-last="true"
cs-suppress-empty-nextprev="true"
cs-remove-nextprev-links="false"
cs-suppress-inactive-firstlast="true"
cs-first-page-text="First"
cs-last-page-text="Last"
cs-pager-li-current-class="active"
cs-pager-li-non-active-class="disabled"
asp-controller="Movements"
asp-route-query="#Model.Query"
asp-route-pagesize="#Model.UserMovementsResults.PageSize"
asp-route-startDateFilter="#Model.StartDateFilter.GetValueOrDefault()"
asp-route-endDateFilter="#Model.EndDateFilter.GetValueOrDefault()"
asp-action="Details" cs-preserve-ambient-querystring="true"></cs-pager>
</div>
}
My Controller (I've tried to set the method HttpGet and HttpPost) →
[HttpGet]
public async Task<IActionResult> Details(int? pageNumber, int? pageSize, int? query, string startDate, string endDate)
{
if (query == null)
{
return NotFound();
}
DateTime startDateFilter = DateTime.Now.StartOfWeek(DayOfWeek.Monday);
DateTime endDateFilter = DateTime.Now.EndOfWeek(DayOfWeek.Monday);
var userMovements = await GetUserMovements(user.Id, pageNumber, pageSize, query, startDateFilter, endDateFilter);
return View(userMovements);
}
}
My ViewModel →
public class UserMovementsViewModel
{
private DateTime? endDateFilter;
public UserMovementsViewModel()
{
UserMovementsResults = new PagedResult<UserMovementsResult>();
}
public string Query { get; set; } = string.Empty;
[Key]
public int Id { get; set; }
public int UserId { get; set; }
public PagedResult<UserMovementsResult> UserMovementsResults { get; set; } = null;
public DateTime? StartDateFilter { get; set; }
public DateTime? EndDateFilter
{
get => endDateFilter;
set
{
if (value != null)
{
endDateFilter = value;
endDateFilter = endDateFilter.Value.AddHours(23).AddMinutes(59).AddSeconds(59);
}
}
}
}
public class UserMovementsResult
{
public DateTime Date { get; set; }
public string Description { get; set; }
}
Here is a simple workaround like below:
1.add the following component in _ViewImports.cshtml:
#using cloudscribe.Web.Pagination
#addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
#addTagHelper "*, cloudscribe.Web.Pagination"
2.Model:
public class UserMovements
{
public string Name { get; set; } = string.Empty;
public DateTime Date { get; set; } = DateTime.UtcNow;
public string Description { get; set; } = string.Empty;
}
public class ViewByDateViewModel
{
public ViewByDateViewModel()
{
UserMovements = new PagedResult<UserMovements>();
}
public PagedResult<UserMovements> UserMovements { get; set; }
public string[] Date { get; set; }
}
3.View(ViewByDate.cshtml):
#using System.Linq
#model ViewByDateViewModel
<form class="form-inline" role="form" asp-controller="Home" asp-action="ViewByDate" method="get" asp-antiforgery="false">
<div class="input-daterange input-group" id="datepicker">
<span style="font-weight:bold">Date</span> From
#Html.TextBox("startDate", null, new
{
id = "startDate",
#class = "input-sm form-control",
})
<span class="input-group-addon"> To </span>
#Html.TextBox("endDate", null, new
{
id = "endDate",
#class = "input-sm form-control",
})
</div>
<input type="submit" value="Browse" class="btn btn-default" />
</form>
#if (Model.UserMovements.Data.Any())
{
<table class="table table-striped table-bordered">
<thead>
<tr>
<th>Name</th>
<th>Date</th>
</tr>
</thead>
<tbody>
#foreach (var product in Model.UserMovements.Data)
{
<tr>
<td>#product.Name</td>
<td>#product.Date</td>
</tr>
}
</tbody>
</table>
<cs-pager cs-paging-pagesize="#Model.UserMovements.PageSize"
cs-paging-pagenumber="#Model.UserMovements.PageNumber"
cs-paging-totalitems="#Model.UserMovements.TotalItems"
cs-pagenumber-param="page"
asp-controller="Home"
asp-action="ViewByDate"
asp-route-categories="#Model.Date.ToCsv()"
asp-route-pagesize="#Model.UserMovements.PageSize"
cs-first-page-text="First"
cs-last-page-text="Last"
cs-previous-page-text="Prev"
cs-next-page-text="Next"></cs-pager>
}
#section Scripts
{
<link rel="stylesheet" href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<script>
$(document).ready(function () {
$("#startDate").datepicker({ format: 'dd/mm/yyyy', autoclose: true, todayBtn: 'linked' });
$("#endDate").datepicker({ format: 'dd/mm/yyyy', autoclose: true, todayBtn: 'linked' })
});
</script>
}
4.Controller:
public class HomeController : Controller
{
private const int DefaultPageSize = 10;
private List<UserMovements> allMovements = new List<UserMovements>();
public HomeController()
{
InitializeMovements();
}
private void InitializeMovements()
{
// Create a list of Movements.
for (var i = 0; i < 527; i++)
{
var userMovements = new UserMovements();
userMovements.Name = "UserMovements " + (i + 1);
var categoryIndex = i % 4;
if (categoryIndex > 2)
{
categoryIndex = categoryIndex - 3;
}
userMovements.Date = DateTime.Now.AddDays(i);
allMovements.Add(userMovements);
}
}
public IActionResult ViewByDate(string startDate, string endDate, int? page)
{
string[] dates = { startDate, endDate };
List<UserMovements> filtered;
var currentPageNum = page.HasValue ? page.Value : 1;
var offset = (DefaultPageSize * currentPageNum) - DefaultPageSize;
var model = new ViewByDateViewModel();
model.Date = dates ?? new string[0];
int currentPageIndex = page.HasValue ? page.Value - 1 : 0;
if (startDate == null && endDate == null)
{
filtered = this.allMovements.ToList();
}
else
{
filtered = this.allMovements
.Where(p => p.Date.Date >= DateTime.Parse(startDate) && p.Date.Date <= DateTime.Parse(endDate))
.ToList();
}
model.UserMovements.Data = filtered
.Skip(offset)
.Take(DefaultPageSize)
.ToList();
model.UserMovements.PageNumber = currentPageNum;
model.UserMovements.PageSize = DefaultPageSize;
model.UserMovements.TotalItems = filtered.Count;
return View(model);
}
}
5.Result:
UPDATE:
1.Model:
public class ViewByDateViewModel
{
private DateTime? endDateFilter;
public ViewByDateViewModel()
{
UserMovements = new PagedResult<UserMovements>();
}
public PagedResult<UserMovements> UserMovements { get; set; }
//public string[] Date { get; set; }
public DateTime? StartDateFilter { get; set; }
public DateTime? EndDateFilter
{
get => endDateFilter;
set
{
if (value != null)
{
endDateFilter = value;
endDateFilter = endDateFilter.Value.AddHours(23).AddMinutes(59).AddSeconds(59);
}
}
}
}
2.View:
#using System.Linq
#model ViewByDateViewModel
<form class="form-inline" role="form" asp-controller="Home" asp-action="ViewByDate" method="get" asp-antiforgery="false">
<div class="input-daterange input-group" id="datepicker">
<span style="font-weight:bold">Date</span> From
#Html.TextBox("startDate", null, new
{
id = "startDate",
#class = "input-sm form-control",
})
<span class="input-group-addon"> To </span>
#Html.TextBox("endDate", null, new
{
id = "endDate",
#class = "input-sm form-control",
})
</div>
<input type="submit" value="Browse" class="btn btn-default" />
</form>
#if (Model.UserMovements.Data.Any())
{
<table class="table table-striped table-bordered">
<thead>
<tr>
<th>Name</th>
<th>Date</th>
</tr>
</thead>
<tbody>
#foreach (var product in Model.UserMovements.Data)
{
<tr>
<td>#product.Name</td>
<td>#product.Date</td>
</tr>
}
</tbody>
</table>
<cs-pager cs-paging-pagesize="#Model.UserMovements.PageSize"
cs-paging-pagenumber="#Model.UserMovements.PageNumber"
cs-paging-totalitems="#Model.UserMovements.TotalItems"
cs-pagenumber-param="page"
asp-controller="Home"
asp-action="ViewByDate"
asp-route-pagesize="#Model.UserMovements.PageSize"
asp-route-startDateFilter="#Model.StartDateFilter"
asp-route-endDateFilter="#Model.EndDateFilter"
cs-first-page-text="First"
cs-last-page-text="Last"
cs-previous-page-text="Prev"
cs-next-page-text="Next"></cs-pager>
}
#section Scripts
{
<link rel="stylesheet" href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<script>
$(document).ready(function () {
$("#startDate").datepicker({ format: 'dd/mm/yyyy', autoclose: true, todayBtn: 'linked' });
$("#endDate").datepicker({ format: 'dd/mm/yyyy', autoclose: true, todayBtn: 'linked' })
});
</script>
}
3.Controller:
public IActionResult ViewByDate(string startDate, string endDate, int? page)
{
string[] dates = { startDate, endDate };
List<UserMovements> filtered;
var currentPageNum = page.HasValue ? page.Value : 1;
var offset = (DefaultPageSize * currentPageNum) - DefaultPageSize;
var model = new ViewByDateViewModel();
model.StartDateFilter = startDate==null? DateTime.Now:DateTime.Parse(startDate);
model.EndDateFilter = endDate == null ? DateTime.Now : DateTime.Parse(endDate);
int currentPageIndex = page.HasValue ? page.Value - 1 : 0;
if (startDate == null && endDate == null)
{
filtered = this.allMovements.ToList();
}
else
{
filtered = this.allMovements
.Where(p => p.Date.Date >= DateTime.Parse(startDate) && p.Date.Date <= DateTime.Parse(endDate))
.ToList();
}
model.UserMovements.Data = filtered
.Skip(offset)
.Take(DefaultPageSize)
.ToList();
model.UserMovements.PageNumber = currentPageNum;
model.UserMovements.PageSize = DefaultPageSize;
model.UserMovements.TotalItems = filtered.Count;
return View(model);
}
if you want to send by url,url would be like:https://localhost:44367/Home/ViewByDate?startdate=11-14-2019&enddate=11-27-2019
If anyone needs this too, here is how I got it → I was missing the setting of the parameters in the controller with ViewBag. Like this → ViewBag.StartDateFilter = starDate; Otherwise, It was becoming at null always, when I tried to change at another page. I don't why.
I used a hidden field too to save the "query" (in my case this is the user id) because when I sent the request submit in the button, this was losing its value too. What a mess !!
Here is a minified version
View:
<script src="~/lib/bootstrap/bootstrap-datepicker/js/bootstrap-datepicker.js"></script>
<form class="form-inline" role="form" asp-controller="Movements" asp-action="Details" method="get" asp-antiforgery="false" asp-route-query="#ViewBag.Query">
<div>
<div class="input-daterange input-group" id="datepicker">
<span style="font-weight:bold">Date</span> From
#Html.TextBox("startDate", null, new
{
id = "startDate",
#class = "input-sm form-control",
#readonly = "readonly"
})
<span class="input-group-addon"> To </span>
#Html.TextBox("endDate", null, new
{
id = "endDate",
#class = "input-sm form-control",
#readonly = "readonly"
})
</div>
<button asp-route-query="#ViewBag.Query" type="submit" value="Filter" name="Filter">Apply</button>
#Html.Hidden("Query", (object)ViewBag.Query)
</div>
</form>
<br />
<table>
<thead>
<tr>
<th>
#Html.DisplayNameFor(model => model.UserMovementsResults.Data.FirstOrDefault().Date)
</th>
<th>
#Html.DisplayNameFor(model => model.UserMovementsResults.Data.FirstOrDefault().Description)
</th>
</tr>
</thead>
<tbody>
#foreach (var item in Model.UserMovementsResults.Data)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.Date)
</td>
<td>
#Html.DisplayFor(modelItem => item.Description)
</td>
</tr>
}
</tbody>
</table>
<div>
<cs-pager cs-paging-pagesize="#Model.UserMovementsResults.PageSize"
cs-paging-pagenumber="#Model.UserMovementsResults.PageNumber"
cs-paging-totalitems="#Model.UserMovementsResults.TotalItems"
cs-pagenumber-param="pageNumber"
asp-controller="Movements"
asp-action="Details"
asp-route-query="#ViewBag.Query"
asp-route-pagesize="#Model.UserMovementsResults.PageSize"
cs-preserve-ambient-querystring="true"
asp-route-startDate="#ViewBag.StartDateFilter"
asp-route-endDate="#ViewBag.EndDateFilter">
</cs-pager>
</div>
Controller:
[HttpGet]
public async Task<IActionResult> Details(int? pageNumber, UserMovementsViewModel userMovementsViewModel)
{
userMovementsViewModel.StartDateFilter = DateTime.ParseExact(userMovementsViewModel.StartDate, "dd/MM/yyyy", CultureInfo.InvariantCulture);
userMovementsViewModel.EndDateFilter = DateTime.ParseExact(userMovementsViewModel.EndDate, "dd/MM/yyyy", CultureInfo.InvariantCulture).SetEndOfDay();
var userMovements = await GetUserMovements(pageNumber, userMovementsViewModel).ConfigureAwait(true);
ViewBag.StartDateFilter = userMovementsViewModel.StartDateFilter.Value.ToString("dd/MM/yyyy", CultureInfo.InvariantCulture);
ViewBag.EndDateFilter = userMovementsViewModel.EndDateFilter.Value.ToString("dd/MM/yyyy", CultureInfo.InvariantCulture);
ViewBag.Query = userMovementsViewModel.Query;
return View(userMovements);
}
My Class:
public class UserMovementsViewModel
{
public UserMovementsViewModel()
{
UserMovementsResults = new PagedResult<UserMovementsResult>();
}
public string Query { get; set; } = string.Empty;
public PagedResult<UserMovementsResult> UserMovementsResults { get; set; } = null;
public DateTime? StartDateFilter { get; set; }
public DateTime? EndDateFilter { get; set; }
public string StartDate { get; set; }
public string EndDate { get; set; }
}
My GET method of controller construct and fill Model, which including Dictionary<int, MyClass>, and transmit that to View. But after, POST controller method get not null model with empty Dictionary.
Model:
public class CheckBoxItem
{
public string Name { get; set; }
public double Data { get; set; }
public bool Selected { get; set; }
}
public class CreateNewEventModel
{
[Required(ErrorMessage = "Error text")]
[Display(Name = "Header name")]
public string EventName { get; set; }
public Dictionary<int, CheckBoxItem> CheckBoxDataItems { get; set; }
public CreateNewEventModel()
{
CheckBoxDataItems = new Dictionary<int, CheckBoxItem>();
}
}
Controller:
public ActionResult CreateEvent()
{
CreateNewEventModel model = new CreateNewEventModel();
// FILL MODEL
foreach (var user in db.UsersInfo.ToList())
{
model.CheckBoxDataItems.Add(user.Id, new CheckBoxItem()
{
Name = user.Name,
Data = 0,
Selected = false
});
}
// THERE IS FULL MODEL
return View(model);
}
[HttpPost]
public ActionResult CreateEvent(CreateNewEventModel model)
{
// THERE IS model.Event name include text
// BUT model.CheckBoxDataItems is empty
if (ModelState.IsValid)
{
...
return View(model);
}
return View(model);
}
View:
#model HLyaa.Models.CreateNewEventModel
#{
ViewBag.Title = "Create Event";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Создание события</h2>
#if (Model.CheckBoxDataItems.Count() != 0)
{
using (Html.BeginForm("CreateEvent", "Events", FormMethod.Post))
{
#Html.ValidationSummary()
<div>
#Html.LabelFor(model => model.EventName)
<div>
#Html.EditorFor(model => model.EventName)
</div>
</div>
<table>
#foreach (var kvpair in Model.CheckBoxDataItems)
{
<tr>
<td>
#Html.CheckBoxFor(model => model.CheckBoxDataItems[kvpair.Key].Selected)
</td>
<td>
#Html.DisplayFor(model => model.CheckBoxDataItems[kvpair.Key].Name)
#Html.HiddenFor(model => model.CheckBoxDataItems[kvpair.Key].Selected)
#Html.HiddenFor(model => model.CheckBoxDataItems[kvpair.Key].Name)
</td>
<td>
#Html.TextBoxFor(model => model.CheckBoxDataItems[kvpair.Key].Data, new { #type = "number" })
</td>
</tr>
}
</table>
<br />
<input type="submit" value="Next" />
}
}
How I can transmit data inside dictionary from View to Controller?
Dictionary no, List/Array yes, but you will have to make some modifications.
Modify models
public class CheckBoxItem {
public int UserId { get; set; }
public string Name { get; set; }
public double Data { get; set; }
public bool Selected { get; set; }
}
public class CreateNewEventModel {
[Required(ErrorMessage = "Error text")]
[Display(Name = "Header name")]
public string EventName { get; set; }
public List<CheckBoxItem> CheckBoxDataItems { get; set; }
public CreateNewEventModel() {
CheckBoxDataItems = new List<CheckBoxItem>();
}
}
Modify GET method CreateEvent
public ActionResult CreateEvent() {
var model = new CreateNewEventModel();
//...FILL MODEL
foreach (var user in db.UsersInfo.ToList()) {
model.CheckBoxDataItems.Add(new CheckBoxItem() {
UserId = user.Id,
Name = user.Name,
Data = 0,
Selected = false
});
}
// THERE IS FULL MODEL
return View(model);
}
Update View
<table>
#for (var i = 0; i < Model.CheckBoxDataItems.Count; i++) {
<tr>
<td>
#Html.CheckBoxFor(model => model.CheckBoxDataItems[i].Selected)
</td>
<td>
#Html.DisplayFor(model => model.CheckBoxDataItems[i].Name)
#Html.HiddenFor(model => model.CheckBoxDataItems[i].UserId)
#Html.HiddenFor(model => model.CheckBoxDataItems[i].Selected)
#Html.HiddenFor(model => model.CheckBoxDataItems[i].Name)
</td>
<td>
#Html.TextBoxFor(model => model.CheckBoxDataItems[i].Data, new { #type = "number" })
</td>
</tr>
}
</table>
CheckBoxDataItems should be populated now when you post it to controller
As I answered in this post, you need to call "ToArray()[*]" on your dictionary before accessing its key and value so you can specify an index that's used by the ASP model binder to send your data back to the controller. ;)
I've tried several various was to move data from a view to the controller in order to sort a new view, but I am unable to get the data to pass. Here is what I have:
View 1
#model TabCheckout.checkout
#{
ViewBag.Title = "Select the Letter of Your Last Name";
}
<h3>Select the Letter of Your Last Name</h3>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
<div class="col-md-10">
#{int i = 0;
foreach (string letter in ViewBag.Letters)
{
i++;
if (i == 9)
{
i = 0;
#Html.Raw("<br />")
}
else
{
<input type='submit' id='#letter' name='selectletter' value='#letter' formaction='Names' />
}
}
}
</div>
</div>
</div>
}
Controller
public ActionResult Letters(string selectletter)
{
List<string> letters = new List<string>();
for (int y = 0; y < 26; y++)
{
char filter = Convert.ToChar(65 + y);
string letter = filter.ToString();
letters.Add(letter);
}
ViewBag.Letters = letters;
GlobalVariable.selectletter = Convert.ToString(selectletter);
return View(GlobalVariable.selectletter);
}
public ActionResult Names()
{
// var namesrt = from s in db.users
// select s;
// namesrt = namesrt.Where(s => s.LastName.StartsWith(GlobalVariable.letter));
// ViewBag.UserID = new SelectList(namesrt, "UserID", "FullName", null);
ViewBag.UserID = new SelectList(db.users, "UserID", "FullName", null);
return View();
}
View 2
#model TabCheckout.checkout
#{
ViewBag.Title = "Select Your Name";
}
<h3>Select Your Name - #GlobalVariable.selectletter</h3>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
<div class="col-md-10">
#{int i = 0;
foreach (var item in ViewBag.UserID as SelectList)
{
i++;
if (i == 9)
{
i = 0;
#Html.Raw("<br />")
}
else
{
<input type="submit" name="#item.Text" value="#item.Text" formaction="Vehicles">
}
}
}
</div>
</div>
</div>
}
I feel like the majority of the problem has to do with my Controller verbiage. I've tried using request name to string, FormCollection, and the current mess.
Thank you for your help and your understanding of my limited skill level.
Here is the model for full disclosure:
Model
namespace TabCheckout
{
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity.Spatial;
[Table("NewsData_Tab.checkout")]
public partial class checkout
{
public int CheckoutID { get; set; }
[Required]
public int User { get; set; }
[ForeignKey("User")]
public virtual user users { get; set; }
[Required]
public int Vehicle { get; set; }
[ForeignKey("Vehicle")]
public virtual vehicle vehicles { get; set; }
[Required]
public int Equipment { get; set; }
public DateTime TimeOut { get; set; }
public DateTime TimeIn { get; set; }
public checkout()
{
TimeOut = DateTime.Now;
}
}
public static class GlobalVariable
{
public static string selectletter { get; set; }
}
}
public ActionResult Names(FormCollection form)
{
var letter = form["selectletter"];
ViewBag.UserID = new SelectList(db.users, "UserID", "FullName", null);
return View();
}
It works for me!
I need a help of displaying the view of comodities, by excluding the duplicate, but adding quantity to the count
E.g.
Name ComodityModel count SellerName
Iphone 3gs 1 Neal
Iphone 4g 1 Jane
Iphone 3gs 1 Neal
Iphone 3gs 1 Jane
Output should be
Name ComodityModel count SellerName
Iphone 3gs 2 Neal
Iphone 4g 1 Jane
Iphone 3gs 1 Jane
I need to filter it by Comodity model and SellerName. I have database and model Comodity
public class Comodity
{
public int ID { get; set; }
[Required(ErrorMessage = "Name is required")]
public string Name { get; set; }
[Required(ErrorMessage = "Date is required")]
//[DisplayFormat(DataFormatString = "{0:d}")]
[DataType(DataType.Date)]
public DateTime ? RegisterDate { get; set; }
[Required(ErrorMessage = "Comodity Model must be specified")]
public string ComodityModel { get; set; }
[Required(ErrorMessage = "Color must be specified")]
[StringLength(15)]
public string Color { get; set; }
[Required(ErrorMessage = "Price Required")]
[Range(1, 1000, ErrorMessage = "Price must be between $1 and $100")]
[DisplayFormat(DataFormatString = "{0:c}")]
public decimal Price { get; set; }
[Required(ErrorMessage = "Seller name must be specified")]
[StringLength(15)]
public string SellerName { get; set; }
public int CountCom { get; set; }
}
public class ComodityDBContext : DbContext
{
public DbSet<Comodity> Comodities { get; set; }
}
and Controller where I defined Actionresult MyView
public ActionResult MyView(DateTime? startDate, DateTime? endDate, string comModel, string searchString)
{
// if (string.IsNullOrEmpty(comModel))
// {
// return View(comodities);
// }
// else
// {
// return View(comodities.Where(x => x.ComodityModel == comModel));
// }
DateTime dtNow;
dtNow = DateTime.Today;
if (!startDate.HasValue)
{
startDate = new DateTime(dtNow.Year, dtNow.Month, 1);
endDate = startDate.Value.AddMonths(1).AddDays(-1);
}
if (startDate.HasValue && !endDate.HasValue)
{
endDate = (new DateTime(startDate.Value.Year, startDate.Value.Month, 1)).AddMonths(1).AddDays(-1);
}
ViewBag.startDate = startDate.Value.ToShortDateString();
ViewBag.endDate = endDate.Value.ToShortDateString();
var viewDate = from r in db.Comodities
where r.RegisterDate >= startDate.Value && r.RegisterDate <= endDate.Value == true
// orderby r.RegisterDate
select r.RegisterDate;
var SelectListName = new List<string>();
var SelectNameQry = from m in db.Comodities
select m.SellerName;
SelectListName.AddRange(SelectNameQry.Distinct());
ViewBag.searchString = new SelectList(SelectListName);
var comModelLst = new List<string>();
var comModelQry = from d in db.Comodities
orderby d.ComodityModel
select d.ComodityModel;
comModelLst.AddRange(comModelQry.Distinct());
ViewBag.comModel = new SelectList(comModelLst);
var comodities = from m in db.Comodities
select m;
IDictionary<string, IList<string>> dict = new Dictionary<string, IList<string>>();
var queryC = from c in db.Comodities
group c by c.ComodityModel into g
where g.Count() > 1
select new { ComodityModel = g.Key, CCount = g.Count() };
foreach (var item in queryC)
{ // comodities = comodities.Where(item => item.Name && item => item.CCount);
//View("", item.ComodityModel, item.CCount);
// ViewBag(item.ComodityModel, item.CCount);
String key = item.ComodityModel;
if (dict.ContainsKey(key))
{
// add the class name into an existing "string" collection
dict[key].Add(item.ComodityModel);
}
else
{
// instantiate a new "string" collection and add the class name.
dict[key] = new List<string> { item.ComodityModel };
}
int maxCourseCount = 0;
foreach (var k in dict.Keys)
{
int valueCount = dict[k].Count;
if (valueCount > maxCourseCount)
maxCourseCount = valueCount;
}
}
if (!String.IsNullOrEmpty(searchString))
{
comodities = comodities.Where(s => s.SellerName.Contains(searchString));
}
if (startDate.HasValue && endDate.HasValue)
{
comodities = comodities.Where(r => r.RegisterDate >= startDate.Value && r.RegisterDate <= endDate.Value);
}
if (string.IsNullOrEmpty(comModel))
{
return View(comodities);
}
else
{
return View(comodities.Where(x => x.ComodityModel == comModel));
}
}
I am new in MVC and have no idea how to count and make view. Please, help. Also, is there some suggestion about date picking. It is showing incorrectly. I assume that it only comparing the day, not whole day-month-year. Thanks in advance
Finally MyView
#model IEnumerable<SaleCenter.Models.Comodity>
#{
ViewBag.Title = "total";
}
<script src="#Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
<h2>total</h2>
<p>
#using (Html.BeginForm()){
<p> startdate:#Html.TextBox("startDate", null, new { #class = "datePicker" })
enddate : #Html.TextBox("endDate", null, new { #class = "datePicker" }) </p>
<p> model: #Html.DropDownList("comModel", "All")
seller: #Html.DropDownList("SearchString", "All")
<input type="submit" value="Total" /></p>
}
</p>
<table>
<tr>
<th>
product name
</th>
<th>
Model
</th>
<th>
seller
</th>
<th>
quantity
</th>
<th>
graphic
</th>
</tr>
#foreach (var item in Model)
{
int w = (int)(2000 * item.CountCom / 100);
<tr>
<td>
#Html.DisplayFor(modelItem => item.Name)
</td>
<td>
#Html.DisplayFor(modelItem => item.ComodityModel)
</td>
<td>
#Html.DisplayFor(modelItem => item.SellerName)
</td>
<td>
#Html.DisplayFor(modelItem => item.CountCom)
</td>
<td>
<img src="#Url.Content("~/Content/Images/graph.gif")" width="#w.ToString()px" height="6px" alt="" />
</td>
</tr>
}
</table>
<script type="text/javascript">
$(document).ready(function () {
$('.datePicker').datepicker({ firstDay: 1, dateFormat: 'dd.mm.yy', showOn: 'button',
buttonImage: '/Content/images/calendar.gif',
duration: 0
});
});
</script>
For showing the commodity and it's count in the view. Quick way it to create a anonymous object from your comodities by grouping with name and get it's count. Return this anonymous object as the model to the view.
Better approach is to create ViewModel specific to this purpose, so that you could create a tightly bound view.
Here is a method to plop into your ComodityController.cs file:
private int getComodityCount(string param_Name, string param_ComodityModel, string param_SellerName)
{
return db.Comodity.Where(x => x.Name == param_Name && x.ComodityModel == param_ComodityModel && x.SellerName == param_SellerName).Count();
}
Now, to get the number of duplicates within the Collection of Comodity you call:
int count = getComodityCount("iPhone","3gs","Neal");
What's more, if you change the privacy setting from private to public, you can even call the method from your view like this:
Here is the method changed to public:
public int getComodityCount(string param_Name, string param_ComodityModel, string param_SellerName)
{
return db.Comodity.Where(x => x.Name == param_Name && x.ComodityModel == param_ComodityModel && x.SellerName == param_SellerName).Count();
}
and here is the code for your View:
#{
int count = new ComodityController().getComodityCount("iPhone","3gs","Neal");
}
I hope this helps. The Where(linq) method is REALLY handy for database querying.