ASP.net MVC - Dynamic Bootstrap Progress Bar in View - asp.net-mvc

I'm trying to use a progress bar in my web application to visually display the number of signatures a cause (petition) has relative to the target number of signatures. Part of the Cause model is a list of Signatures existing in another table. I'm trying to create and add the current variables to the progress bar, but none of my attempts seem to be working and I'm unsure where I'm going wrong. I have tried several permutations of the following code without any success. I just get empty progress bars in the web browser. Any help would be appreciated:
#model IEnumerable<SoWokeWebApp.Models.Cause.Cause>
#{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
}
#foreach (var item in Model)
{
<div class="jumbotron">
<img src="#item.ImageURL" alt="Alternate Text" class="img-fluid" />
<h1>#Html.DisplayFor(model => item.CauseTitle)</h1>
<p>#Html.DisplayFor(model => item.Description)</p>
<p>#item.Signatures.Count</p>
#foreach (var Signature in item.Signatures)
{
<p>#Signature.UserEmail</p>
<p>#Signature.FirstName</p>
}
#{int target = item.TargetSignatures;
int current = item.Signatures.Count;
int progress = current / target * 100;}
<div class="progress">
<div class="progress-bar" role="progressbar" style="width: #progress%" aria-valuenow="#current" aria-valuemin="0" aria-valuemax="#target"></div>
</div>
<p><a class="btn btn-primary btn-lg" href="#" role="button">#Html.ActionLink("Sign Cause", "Create", "Signatures")</a></p>
</div>
The models are as follows:
public class Cause
{
[Key]
[StringLength(100)]
[DisplayName("Cause Title")]
public string CauseTitle { get; set; }
[Required]
[StringLength(500)]
public string Description { get; set; }
[Required]
public string UserEmail { get; set; }
[Required]
[DisplayName("Date Posted")]
public DateTime DatePosted { get; set; }
public string ImageURL { get; set; }
[DisplayName("Catagory")]
public string CatagoryTitle { get; set; }
[ForeignKey("CatagoryTitle")]
public Catagory Catagory { get; set; }
[DisplayName("Signatures Target")]
public int TargetSignatures { get; set; }
public virtual List<Signature> Signatures { get; set; }
}
and
public class Signature
{
[Key]
public int SignatureId { get; set; }
[Required]
public string UserEmail { get; set; }
[Required]
public string FirstName { get; set; }
[Required]
public string LastName { get; set; }
[Required]
public string CauseTitle { get; set; }
[ForeignKey("CauseTitle")]
public virtual Cause Cause { get; set; }
}

I found this neat little trick using SignalR with a Bootstrap Progress Bar in MVC:
SignalR Progress Bar Simple Example - Sending Live Data from Server to Client
I had to tweak ProgressHub.cs and change hubContext.Clients.All to hubContext.Clients.Group(user) or the progress bar messages went to all clients. See: Working with Groups in SignalR
It does seem to generate some traffic.

Related

knockout 3 level mapping, 3rd level doesnt change

I am new to KnockoutJS and I am trying to create a 3-level model binding, for a master-detail ASP.NET MVC view.
here is the screen i am trying to implement this behavior on:
I have the following ViewModel design
public class CreateReservationViewModel
{
public string Title { get; set; }
public String LogoPath { get; set; }
public string StartDate { get; set; }
public string EndDate { get; set; }
public string StartTime { get; set; }
public string EndTime { get; set; }
public int TimeSpan { get; set; }
public int MinPersons { get; set; }
public int MaxPersons { get; set; }
public List<ReservationOptionViewModel> ReservationOptions { get; set; }
public string MessageToClient { get; set; }
public CreateReservationViewModel()
{
ReservationOptions = new List<ReservationOptionViewModel>();
}
}
public class ReservationOptionViewModel
{
public int Id { get; set; }
public string Title { get; set; }
public int TypeId { get; set; }
public string TypeDescription { get; set; }
public string Info { get; set; }
public List<ValuesViewModel> ReservationOptionValues { get; set; }
public ReservationOptionViewModel()
{
ReservationOptionValues = new List<ValuesViewModel>();
}
}
public class ValuesViewModel
{
public int Id { get; set; }
public string ValueTitle { get; set; } // this value i cant seem to get to bind user input always defaults to whatever i set it in knockout
}
and here is my .js and .html https://jsfiddle.net/camLpdty/
Although I am able to successfully bind the first and second levels, 3rd level binding always picks up default values i.e: [({ Id: 0, ValueTitle: "this is read only and cant change"})] }
everything else seems to work...
From your jsfiddle it looks like the binding context for the Values column is a bit off. data-bind="value: Values.ValueTitle" - Here Values is an array but you're trying to bind a single input box to it. It doesn't know which element's ValueTitle to use so it's probably not bound to anything. You'll need to use a "foreach" or change how you're displaying that information
As a quick test you can try changing that last binding from:
<td>
<input class="form-control input-sm"
data-bind="value: ReservationOptionValues.ValueTitle" />
</td>
to
<td data-bind="foreach: ReservationOptionValues">
<input class="form-control input-sm" data-bind="value: ValueTitle" />
</td>
This will create an input box for every element in the Values array so you probably don't want to leave it like this, but it should highlight the knockout-context problem

Login + Register + another model in a single view?

I am trying to find the best solution so that on any given page I always have a login model, a register model and another model (or more). The login and register models are found in the navbar and the footer respectively on each page.
Specifically I have a situation whereby I have a course page which populates from a table depending on which course has been looked up via the url inputted. So the page loads the course page model. On the same page in the header and footer I need to have the login and register forms which both require their own models.
The course page is populated using a foreach loop:
COURSE PAGE VIEW (SHORTENED):
#model IEnumerable<oltinternational_mvc.Models.Course_page>
#{
Layout = "~/Views/Shared/_courselayout.cshtml";
foreach (var cpage in Model) { ViewBag.Title = #cpage.page_title; }
}
#foreach (var cpage in Model)
{
if (cpage.template_type == 2)
{
<div id="main_container">
<article class="content">
<h1>
#cpage.Title
</h1>
<section>
#Html.Raw(cpage.main_image)
<h3>
#cpage.Country
</h3>
<p>#cpage.intro_1</p>
#if (!string.IsNullOrEmpty(cpage.intro_2))
{
<p>#cpage.intro_2</p>
}
#if (!string.IsNullOrEmpty(cpage.intro_3))
{
<p>#cpage.intro_3</p>
}
View sample pages
#if (!string.IsNullOrEmpty(cpage.website_button))
{
#Html.Raw(cpage.website_button)
}
else {
Licensing options
}
#Html.Raw(cpage.popup_script)
<div class="clearfloat"></div>
</section>
</article>
</div>
The controller is as follows:
public ActionResult Course_page(string id)
{
string abbrev = id;
var cpage = from c in db.Course_page
select c;
if (!String.IsNullOrEmpty(abbrev))
{
cpage = cpage.Where(x => x.abbrev.Contains(abbrev));
}
return View(cpage);
}
and the model:
[Table("course_page")]
public class Course_page
{
[Key]
public int CourseID { get; set; }
public string Meta { get; set; }
public string Title { get; set; }
public string Country { get; set; }
public string main_image { get; set; }
public string list_1 { get; set; }
public string list_2 { get; set; }
public string list_3 { get; set; }
public string list_4 { get; set; }
public string list_5 { get; set; }
public string list_6 { get; set; }
public string list_7 { get; set; }
public string list_8 { get; set; }
public string list_9 { get; set; }
public string list_10 { get; set; }
public string testim_1 { get; set; }
public string testim_2 { get; set; }
public string testim_3 { get; set; }
public string course_site { get; set; }
public string popup_script { get; set; }
public string abbrev { get; set; }
public string page_title { get; set; }
public int template_type { get; set; }
public string intro_1 { get; set; }
public string intro_2 { get; set; }
public string intro_3 { get; set; }
public string website_button { get; set; }
}
In the navbar I have the following list item which references my ajax logging in form:
<li class="login">
<span>Login</span>
#using (Ajax.BeginForm("login", "Account", new AjaxOptions
{
HttpMethod = "POST",
UpdateTargetId = "login_box"
}, new { id = "login_box" }))
{
#Html.Partial("_login")
}
</li>
Which loads this form:
#model myproject_mvc.Models.LoginViewModel
<script src="https://www.google.com/recaptcha/api.js" async defer></script>
<div id="login_box">
<div class="sign_up_box"> Sign up in seconds </div>
#Html.ValidationSummary(true)
#Html.AntiForgeryToken()
<div class="login_box_lower">
<p class="login_box_or">or</p>
<p class="login_sign_in">Sign in</p>
<div style="position:relative;">
#Html.EditorFor(model => model.Email, new { htmlAttributes = new { placeholder = "Email", maxlength = "18", #class = "login_username clearable" } })
<span class="login_username_icon"></span>
</div>
<div style="position:relative;">
#Html.EditorFor(model => model.Password, new { htmlAttributes = new { placeholder = "Password", maxlength = "18", #class = "login_pw clearable" } })
<span class="login_pw_icon"></span>
</div>
Login
<div class="clearfloat"></div>
Forgot password?
</div>
</div>
With the following model:
public class LoginViewModel
{
[Required]
[Display(Name = "Email")]
[EmailAddress]
public string Email { get; set; }
[Required]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string Password { get; set; }
[Display(Name = "Remember me?")]
public bool RememberMe { get; set; }
}
The same situation is such for the Register form in the footer, which uses the RegisterViewModel. Bearing in mind the actual form above for logging in isn't completed yet, it just directs to a /account url for now.
I've tried a few solutions I've found online but can't seem to make any of them work, I think in part because I am using foreach to populate the view from the course page model. I don't see how I can use a viewmodel because I am using a foreach loop on the page.
What I would like to know is what is the best way to deal with this situation?
You should create and use viewmodel(s) instead of directly referencing your objects. Perhaps something like this.
Create a new class, MyViewModel.cs (or whatever name you prefer)
public class MyViewModel
{
public IEnumerable<oltinternational_mvc.Models.Course_page> CoursePages { get; set; }
public myproject_mvc.Models.LoginViewModel { get; set; }
}
Now in your view, instead of referencing the models directly, you would reference the view model. Something like #model myproject_mvc.ViewModels.MyViewModel
In your foreach loop you would so something like this #foreach (var cpage in Model.CoursePages)

Grid MVC how to add the details section

I have been using Grid.Mvc to display some records for a while now, however as more and more properties have been added to the model, the grid has become ugly and too busy.
So I revisted the Grid.Mvc documentation pages and realised that in the demo provided:
http://gridmvc.azurewebsites.net/
They are rather neatly displaying full details of the record in a div on the right hand side of the page under the title Order details, meaning the actual grid does not get bogged down with the finer details.
I want to implement this to my project but I cannot work out how this works, there seems to be no documentation on the website that I can find that explains this, even though it seems to be used in every example they show. When I click view source I cannot see any source for how the data is being retrieved asynchronously per row.
How do I add a details section for each selected row as per the example linked?
edit: Object im passing back as JSON
public class MasterEmailViewModel
{
public int EmailId { get; set; }
public int MvpId { get; set; }
public string FirstName { get; set; }
public string Surname { get; set; }
public string AddressLineOneOld { get; set; }
public string AddressLineTwoOld { get; set; }
public string AddressLineThreeOld { get; set; }
public string AddressLineFourOld { get; set; }
public string AddressLineFiveOld { get; set; }
public string PostcodeOld { get; set; }
public string AddressLineOneNew { get; set; }
public string AddressLineTwoNew { get; set; }
public string AddressLineThreeNew { get; set; }
public string AddressLineFourNew { get; set; }
public string AddressLineFiveNew { get; set; }
public string PostcodeNew { get; set; }
public bool IsChecked { get; set; }
public string Comment { get; set; }
//navigation prop
}
I have done the exact same thing with one of my projects.
The example is just using a jquery $post
View
<div class="row">
<div class="col-md-3 col-md-push-9">
<h4>Order details
</h4>
<div id="emailId">
<p class="muted">
Select order to display detailed infomation
</p>
</div>
<div id="firstNameId">
</div>
</div>
<div class="col-md-9 col-md-pull-3">
//Grid stuff
</div>
</div>
JS
$(function () {
// ordersGrid is what you called your Grid e.g. #Html.Grid(Model).Named("ordersGrid")
pageGrids.ordersGrid.onRowSelect(function (e) {
$.post("/Home/GetOrder?id=" + e.row.OrderID, function (data) {
if (data.Status <= 0) {
alert(data.Message);
return;
}
// Replace the data
$("#emailId").html(data.EmailId);
$('#firstNameId').html(data.FirstName);
});
});
});
Controller
[HttpPost]
public ActionResult GetOrder(int id)
{
// Get the data
return Json(data);
}

Model returning date value as required although it is not null in table

I have a asp mvc 5 project using entity framework code-first. I created the controllers and views with scaffolding. Although i have not specified in the model that the Due date be [Required] and the item in the table has a value of NOT NULL.
Yet I am still getting this message on the POST
The DueDate field is required.
The model is really basic
public class Project
{
public int ProjectId { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public DateTime StartDate { get; set; }
public DateTime DueDate { get; set; }
public int ClientId { get; set; }
public virtual Client Client { get; set; }
}
}
This is a Datetime2 datatype using EditorFor
<div class="input-group">
#Html.EditorFor(model => model.DueDate, new { #class = "form-control datepicker" })
<div class="input-group-addon">
<i class="entypo-calendar"></i>
</div>
</div>
It is also using jquery bootstrap datepicker, Although i doubt these has any effect on this functionality. Really confused how this field is a required field yet it has not been set as such in any area of the solution or database.
That's normal. DateTime is a value type meaning that it will always require a value. The model metadeata provider in ASP.NET MVC automatically adds the required attribute to non-nullable data types. You could use a nullable DateTime:
public class Project
{
public int ProjectId { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public DateTime StartDate { get; set; }
public DateTime? DueDate { get; set; }
public int ClientId { get; set; }
public virtual Client Client { get; set; }
}

ASP.NET display related detail records via Razor

I am new to asp.net and c#, I have been trying to duplicate and app done in php using MVC3, generating the code from the same database. I have a question about showing the detail records in my "Details" view.
namespace MvcApplication5.Models
{
[DataContract(IsReference = true)]
[KnownType(typeof(masterDomain))]
[KnownType(typeof(masterFIP))]
[KnownType(typeof(masterSFPF))]
[KnownType(typeof(rgCountiesServed))]
[KnownType(typeof(rgKeyword))]
[KnownType(typeof(rgServicesProvided))]
public partial class rgOrganization
{
public rgOrganization()
{
this.rgCountiesServeds = new HashSet<rgCountiesServed>();
this.rgKeywords = new HashSet<rgKeyword>();
this.rgServicesProvideds = new HashSet<rgServicesProvided>();
}
[DataMember]
public int orgID { get; set; }
[DataMember]
public string ORGANIZATION { get; set; }
[DataMember]
public string CONTACT_PERSON { get; set; }
[DataMember]
public string PHONE_NUMBER { get; set; }
[DataMember]
public string FAX_NUMBER { get; set; }
[DataMember]
public string EMAIL_ADDRESS { get; set; }
[DataMember]
public string WEBSITE { get; set; }
[DataMember]
public string STREET_1 { get; set; }
[DataMember]
public string STREET_2 { get; set; }
[DataMember]
public string CITY { get; set; }
[DataMember]
public string ZIP_CODE { get; set; }
[DataMember]
public string COUNTY { get; set; }
[DataMember]
public string FIPS { get; set; }
[DataMember]
public string MAILING_ADDRESS { get; set; }
[DataMember]
public Nullable<int> SFPF { get; set; }
[DataMember]
public Nullable<int> DOMAIN { get; set; }
[DataMember]
public virtual masterDomain masterDomain { get; set; }
[DataMember]
public virtual masterFIP masterFIP { get; set; }
[DataMember]
public virtual masterSFPF masterSFPF { get; set; }
[DataMember]
public virtual ICollection<rgCountiesServed> rgCountiesServeds { get; set; }
[DataMember]
public virtual ICollection<rgKeyword> rgKeywords { get; set; }
[DataMember]
public virtual ICollection<rgServicesProvided> rgServicesProvideds { get; set; }
}
View Code
#model MvcApplication5.Models.rgOrganization
#{
ViewBag.Title = #Html.DisplayFor(model => model.ORGANIZATION);
}
#section Scripts {
<script type="text/javascript"
src="http://maps.google.com/maps/api/js?sensor=false"></script>
}
<h2>#Html.DisplayFor(model => model.ORGANIZATION)</h2>
<h3><span id="mailing_address">
#Html.DisplayFor(model => model.MAILING_ADDRESS)
</span></h3>
<fieldset>
<legend> #Html.DisplayFor(model => model.COUNTY) COUNTY</legend>
<div class="display-field">
<strong>#Html.DisplayFor(model => model.ORGANIZATION)</strong>
</div>
<div class="display-field">
#Html.DisplayFor(model => model.CONTACT_PERSON)
</div>
<!-- would like to display services provided here -->
</fieldset>
My question is how do I access the 'rgCountiesServeds'and 'rgServicesProvideds' via Razor?
They appear to be members of your model.
So you can access the collection as
model.rgServicesProvided
To iterate through the collection, do something like this:
#foreach (var serv in model.ServicesProvided) {
Service is #serv.ToString()<br/>
}
Replace serv.ToString() with whatever property you want to display.
If I understand what you're asking, you can access the rgCountiedServeds and rgServicesProvideds just like the other properties of rgOrganization. They are collections and properties of your model so you can loop over them in the View or create a drop down list for each of those properties. I.e.,
#Html.DropDownList("DropDownCounties", Model.rgCountiesServeds)

Resources