MusicStore.Spa changes:

- Make the account manage page work
- Changed ngTextBoxFor extension not use the base TextBoxFor helper as it was adding unwanted client validation attributes
- Fix controller route
This commit is contained in:
DamianEdwards 2014-06-16 18:09:08 -07:00
parent 4a4fe86df4
commit 7ec9c71181
5 changed files with 36 additions and 26 deletions

View File

@ -99,9 +99,8 @@ namespace MusicStore.Controllers
//
// GET: /Account/Manage
//Bug: https://github.com/aspnet/WebFx/issues/339
[HttpGet]
public IActionResult Manage(ManageMessageId? message)
public IActionResult Manage(ManageMessageId? message = null)
{
ViewBag.StatusMessage =
message == ManageMessageId.ChangePasswordSuccess ? "Your password has been changed."

View File

@ -12,14 +12,12 @@ namespace Microsoft.AspNet.Mvc.Rendering
{
public static HtmlString ngPasswordFor<TModel, TProperty>(this IHtmlHelper<TModel> html, Expression<Func<TModel, TProperty>> expression)
{
return html.ngTextBoxFor(expression, new RouteValueDictionary { { "type", "password" } });
return html.ngPasswordFor(expression, null);
}
public static HtmlString ngPasswordFor<TModel, TProperty>(this IHtmlHelper<TModel> html, Expression<Func<TModel, TProperty>> expression, object htmlAttributes)
{
return html.ngTextBoxFor(expression, MergeAttributes(
new RouteValueDictionary { { "type", "password" } },
HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes)));
return html.ngPasswordFor(expression, HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes));
}
public static HtmlString ngPasswordFor<TModel, TProperty>(this IHtmlHelper<TModel> html, Expression<Func<TModel, TProperty>> expression, IDictionary<string, object> htmlAttributes)
@ -51,8 +49,12 @@ namespace Microsoft.AspNet.Mvc.Rendering
var metadata = ExpressionMetadataProvider.FromLambdaExpression(expression, helper.ViewData, helper.ModelMetadataProvider);
var ngAttributes = new Dictionary<string, object>();
ngAttributes["type"] = "text";
// Angular binding to client-side model (scope). This is required for Angular validation to work.
ngAttributes["ng-model"] = html.ViewData.TemplateInfo.GetFullHtmlFieldName(expressionText);
var valueFieldName = html.ViewData.TemplateInfo.GetFullHtmlFieldName(expressionText);
ngAttributes["name"] = valueFieldName;
ngAttributes["ng-model"] = valueFieldName;
// Set input type
if (string.Equals(metadata.DataTypeName, Enum.GetName(typeof(DataType), DataType.EmailAddress), StringComparison.OrdinalIgnoreCase))
@ -139,7 +141,14 @@ namespace Microsoft.AspNet.Mvc.Rendering
}
// Render!
return html.TextBoxFor(expression, null, MergeAttributes(ngAttributes, htmlAttributes));
if (metadata.Model != null)
{
ngAttributes.Add("value", metadata.Model.ToString());
}
var tag = new TagBuilder("input");
tag.MergeAttributes(MergeAttributes(ngAttributes, htmlAttributes));
return tag.ToHtmlString(TagRenderMode.SelfClosing);
}
//private static bool IsNumberType(Type type)
@ -255,7 +264,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
tag.MergeAttributes(htmlAttributes, replaceExisting: true);
return html.Raw(tag.ToString());
return tag.ToHtmlString(TagRenderMode.Normal);
}
public static HtmlString ngValidationMessageFor<TModel, TProperty>(this IHtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, string formName)
@ -341,6 +350,11 @@ namespace Microsoft.AspNet.Mvc.Rendering
private static IDictionary<string, object> MergeAttributes(IDictionary<string, object> source, IDictionary<string, object> target)
{
if (target == null)
{
return source;
}
// Keys in target win over keys in source
foreach (var pair in source)
{

View File

@ -78,7 +78,7 @@ namespace MusicStore.Spa
routes.MapRoute(null, "api/albums/mostPopular", new { controller = "AlbumsApi", action = "MostPopular" });
routes.MapRoute(null, "api/albums/all", new { controller = "AlbumsApi", action = "All" });
routes.MapRoute(null, "api/albums/{albumId}", new { controller = "AlbumsApi", action = "Details" });
routes.MapRoute(null, "{controller}/{action}", new { controller = "Home", action = "Index" });
routes.MapRoute(null, "{controller}/{action}/{id?}", new { controller = "Home", action = "Index" });
});
}
}

View File

@ -2,9 +2,11 @@
//TODO: Until we have a way to specify the layout page at application level.
Layout = "/Views/Shared/_Layout.cshtml";
ViewBag.Title = "Manage Account";
ViewBag.ngApp = "MusicStore.Store";
}
<h2>@ViewBag.Title.</h2>
<p class="text-success">@ViewBag.StatusMessage</p>
<div class="row">
@ -14,8 +16,9 @@
</div>
@section Scripts {
@*TODO : Until script helpers are available, adding script references manually*@
@*@Scripts.Render("~/bundles/jqueryval")*@
<script src="@Url.Content("~/Scripts/jquery.validate.js")"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.js")"></script>
<script src="~/js/angular.js"></script>
<script src="~/js/angular-route.js"></script>
@* TODO: This is currently all the compiled TypeScript, non-minified. Need to explore options
for alternate loading schemes, e.g. AMD loader of individual modules, min vs. non-min, etc. *@
<script src="~/js/MusicStore.Store.js"></script>
}

View File

@ -1,18 +1,14 @@
@using System.Security.Principal
@model MusicStore.Models.ManageUserViewModel
<p>You're logged in as <strong>@Context.HttpContext.User.Identity.GetUserName()</strong>.</p>
<p>You're logged in as <strong>@User.Identity.GetUserName()</strong>.</p>
@using (Html.BeginForm("Manage", "Account", FormMethod.Post,
new
{
@class = "form-horizontal",
role = "form",
novalidate = "",
name = "changePassword",
app_prevent_submit = "changePassword.$invalid",
ng_submit = "changePassword.submitAttempted=true"
}))
new { @class = "form-horizontal",
role = "form", novalidate = "", name = "changePassword",
app_prevent_submit = "changePassword.$invalid",
ng_submit = "changePassword.submitAttempted=true" }))
{
@Html.AntiForgeryToken()
<h4>Change Password</h4>
@ -60,6 +56,4 @@
<button type="submit" class="btn btn-primary">Change password</button>
</div>
</div>
}
}