From 7ec9c7118135c34c14388c4db3f649f66b691e79 Mon Sep 17 00:00:00 2001 From: DamianEdwards Date: Mon, 16 Jun 2014 18:09:08 -0700 Subject: [PATCH] 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 --- .../Controllers/AccountController.cs | 3 +- .../Helpers/AngularExtensions.cs | 28 ++++++++++++++----- src/MusicStore.Spa/Startup.cs | 2 +- .../Views/Account/Manage.cshtml | 11 +++++--- .../Account/_ChangePasswordPartial.cshtml | 18 ++++-------- 5 files changed, 36 insertions(+), 26 deletions(-) diff --git a/src/MusicStore.Spa/Controllers/AccountController.cs b/src/MusicStore.Spa/Controllers/AccountController.cs index 5ee06b9dee..19270f19af 100644 --- a/src/MusicStore.Spa/Controllers/AccountController.cs +++ b/src/MusicStore.Spa/Controllers/AccountController.cs @@ -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." diff --git a/src/MusicStore.Spa/Helpers/AngularExtensions.cs b/src/MusicStore.Spa/Helpers/AngularExtensions.cs index 7465305434..f3ee6993bd 100644 --- a/src/MusicStore.Spa/Helpers/AngularExtensions.cs +++ b/src/MusicStore.Spa/Helpers/AngularExtensions.cs @@ -12,14 +12,12 @@ namespace Microsoft.AspNet.Mvc.Rendering { public static HtmlString ngPasswordFor(this IHtmlHelper html, Expression> expression) { - return html.ngTextBoxFor(expression, new RouteValueDictionary { { "type", "password" } }); + return html.ngPasswordFor(expression, null); } public static HtmlString ngPasswordFor(this IHtmlHelper html, Expression> 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(this IHtmlHelper html, Expression> expression, IDictionary htmlAttributes) @@ -51,8 +49,12 @@ namespace Microsoft.AspNet.Mvc.Rendering var metadata = ExpressionMetadataProvider.FromLambdaExpression(expression, helper.ViewData, helper.ModelMetadataProvider); var ngAttributes = new Dictionary(); + 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(this IHtmlHelper htmlHelper, Expression> expression, string formName) @@ -341,6 +350,11 @@ namespace Microsoft.AspNet.Mvc.Rendering private static IDictionary MergeAttributes(IDictionary source, IDictionary target) { + if (target == null) + { + return source; + } + // Keys in target win over keys in source foreach (var pair in source) { diff --git a/src/MusicStore.Spa/Startup.cs b/src/MusicStore.Spa/Startup.cs index 61f1d6dbbf..706b2648f7 100644 --- a/src/MusicStore.Spa/Startup.cs +++ b/src/MusicStore.Spa/Startup.cs @@ -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" }); }); } } diff --git a/src/MusicStore.Spa/Views/Account/Manage.cshtml b/src/MusicStore.Spa/Views/Account/Manage.cshtml index fef49f927d..0f89881bec 100644 --- a/src/MusicStore.Spa/Views/Account/Manage.cshtml +++ b/src/MusicStore.Spa/Views/Account/Manage.cshtml @@ -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"; }

@ViewBag.Title.

+

@ViewBag.StatusMessage

@@ -14,8 +16,9 @@
@section Scripts { - @*TODO : Until script helpers are available, adding script references manually*@ - @*@Scripts.Render("~/bundles/jqueryval")*@ - - + + + @* 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. *@ + } \ No newline at end of file diff --git a/src/MusicStore.Spa/Views/Account/_ChangePasswordPartial.cshtml b/src/MusicStore.Spa/Views/Account/_ChangePasswordPartial.cshtml index c3e2573be9..d6c3c25b19 100644 --- a/src/MusicStore.Spa/Views/Account/_ChangePasswordPartial.cshtml +++ b/src/MusicStore.Spa/Views/Account/_ChangePasswordPartial.cshtml @@ -1,18 +1,14 @@ @using System.Security.Principal + @model MusicStore.Models.ManageUserViewModel -

You're logged in as @Context.HttpContext.User.Identity.GetUserName().

+

You're logged in as @User.Identity.GetUserName().

@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()

Change Password

@@ -60,6 +56,4 @@ -} - } \ No newline at end of file