From bffdc71f4c8359e9d418bb5e6eef4ee12286e72b Mon Sep 17 00:00:00 2001 From: Dan Pettersson Date: Sat, 15 Jul 2017 07:06:53 +0200 Subject: [PATCH] Creating the AureliaBindTagHelper to render Aurelia bindings for ASP.NET MVC model members --- .../TagHelpers/AureliaBindTagHelper.cs | 139 ++++++++++++++++++ src/FooBar.Web/Views/Home/Person.cshtml | 15 +- 2 files changed, 148 insertions(+), 6 deletions(-) create mode 100644 src/FooBar.Web/TagHelpers/AureliaBindTagHelper.cs diff --git a/src/FooBar.Web/TagHelpers/AureliaBindTagHelper.cs b/src/FooBar.Web/TagHelpers/AureliaBindTagHelper.cs new file mode 100644 index 0000000..cae551b --- /dev/null +++ b/src/FooBar.Web/TagHelpers/AureliaBindTagHelper.cs @@ -0,0 +1,139 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc.ViewFeatures; +using Microsoft.AspNetCore.Razor.TagHelpers; + +namespace FooBar.Web.TagHelpers +{ + [HtmlTargetElement(Attributes = VkAuBindPrefix + "*")] + public class AureliaBindTagHelper : TagHelper + { + private const string VkAuBindPrefix = "th-au-bind-"; + private const string VkAuValueConvertersPrefix = "th-au-value-converters-"; + private const string VkAuBindingBehaviorsPrefix = "th-au-binding-behaviors-"; + + private IDictionary _allModels; + /// + /// If attribute is foo and MVC Model member is Bar; th-au-bind-foo="Bar" + /// To change binding type from default .bind; th-au-bind-foo.one-time="Bar" (other possibles are .one-way and .two-way) + /// + [HtmlAttributeName("th-au-all-models", DictionaryAttributePrefix = VkAuBindPrefix)] + public IDictionary AllModels { + get { + return _allModels ?? + (_allModels = new Dictionary(StringComparer.OrdinalIgnoreCase)); + } + set { + _allModels = value; + } + } + + private IDictionary _allValueConverters; + /// + /// Aurelia Value Converters to use for each binding. If multiple separate with |. + /// To set for attribute foo: th-au-value-converters-foo="conv1" + /// + [HtmlAttributeName("th-au-all-value-converters", DictionaryAttributePrefix = VkAuValueConvertersPrefix)] + public IDictionary AllValueConverters { + get { + return _allValueConverters ?? + (_allValueConverters = new Dictionary(StringComparer.OrdinalIgnoreCase)); + } + set { + _allValueConverters = value; + } + } + + private IDictionary _allBindingBehaviors; + /// + /// Aurelia Binding Behaviours to use for each binding. If multiple separate with &. + /// To set for attribute foo: th-au-binding-behaviors-foo="beh1" + /// + [HtmlAttributeName("th-au-all-binding-behaviors", DictionaryAttributePrefix = VkAuBindingBehaviorsPrefix)] + public IDictionary AllBindingBehaviors { + get { + return _allBindingBehaviors ?? + (_allBindingBehaviors = new Dictionary(StringComparer.OrdinalIgnoreCase)); + } + set { + _allBindingBehaviors = value; + } + } + + public override void Process(TagHelperContext context, TagHelperOutput output) + { + foreach (KeyValuePair item in AllModels) + { + string attributeName = item.Key; + string bindType = "bind"; + if (attributeName.Contains(".")) + { + var parts = attributeName.Split('.'); + attributeName = parts[0]; + bindType = parts[1]; + } + + string expression = BuildExpression(item.Value); + + string valueConverters = ""; + if (AllValueConverters.ContainsKey(attributeName)) + { + valueConverters = AllValueConverters[attributeName]; + } + + string bindingBehaviors = ""; + if (AllBindingBehaviors.ContainsKey(attributeName)) + { + bindingBehaviors = AllBindingBehaviors[attributeName]; + } + + expression = AddConvertersAndBehaviors(expression, valueConverters, bindingBehaviors); + + output.Attributes.SetAttribute(attributeName + "." + bindType, expression); + } + } + + public static string BuildExpression(ModelExpression model) + { + string name = model.Name; + + if (String.IsNullOrEmpty(name)) + { + throw new InvalidOperationException("AureliaGenericBindTagHelper could not resolve name from the given ModelExpression."); + } + + string result = string.Empty; + string[] parts = name.Split('.'); + for (int i = 0; i < parts.Length; i++) + { + if (i > 0) + { + result += "."; + } + string part = parts[i][0].ToString().ToLowerInvariant() + parts[i].Substring(1); //Make camelCase; + result += part; + } + result = "data." + result; //"data" is by convention the name of any MVC Model added as data to a client side model. + return result; + } + + public static string AddConvertersAndBehaviors(string bindExpression, string valueConverters, string bindingBehaviors) + { + string result = bindExpression; + + if (!String.IsNullOrWhiteSpace(valueConverters)) + { + result += " | " + valueConverters; + } + + if (!String.IsNullOrWhiteSpace(bindingBehaviors)) + { + result += " & " + bindingBehaviors; + } + + return result; + } + } +} \ No newline at end of file diff --git a/src/FooBar.Web/Views/Home/Person.cshtml b/src/FooBar.Web/Views/Home/Person.cshtml index adfc48a..b050860 100644 --- a/src/FooBar.Web/Views/Home/Person.cshtml +++ b/src/FooBar.Web/Views/Home/Person.cshtml @@ -1,5 +1,5 @@ @{ - ViewData["Title"] = "Person"; + ViewData["Title"] = "Person"; } @model FooBar.Web.Models.PersonModel @@ -7,7 +7,7 @@

Edit Person

- @if(ViewData.ContainsKey("Feedback")) + @if (ViewData.ContainsKey("Feedback")) {
@ViewData["Feedback"] @@ -17,17 +17,20 @@
- +
- +
-
${data.firstName} ${data.lastName}
+
+ + +
@@ -37,7 +40,7 @@
- +