Created
October 20, 2016 22:04
-
-
Save tabula-rasa/c1d53131b940953efdf661b012ddd130 to your computer and use it in GitHub Desktop.
Core.NET Razor-like html helpers (input, label) for mithril js - example (with some es6 syntax mixed in)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using Microsoft.AspNetCore.Mvc.ModelBinding; | |
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
namespace Catalog.Models | |
{ | |
public class ApiModel | |
{ | |
public ApiModel(IModelMetadataProvider MetadataProvider, Type childType) | |
{ | |
if (MetadataProvider != null) //is null, when initialized by binder on POST requests | |
{ | |
this.Meta = MetadataProvider.GetMetadataForProperties(childType).Select(x => new MetaData | |
{ | |
PropertyName = x.PropertyName, //name of the property | |
DisplayName = x.DisplayName, //display name | |
IsRequired = x.IsRequired, //required attribute | |
IsReadOnly = x.IsReadOnly, //IsEditable(false) attribue | |
DataTypeName = x.DataTypeName, //DataType attr | |
Placeholder = x.Placeholder, //Placeholder attr, don't using it in this ex tho | |
}); | |
} | |
} | |
public IEnumerable<MetaData> Meta { get; set; } | |
} | |
public class MetaData | |
{ | |
public string PropertyName { get; set; } | |
public string DisplayName { get; set; } | |
public bool IsRequired { get; set; } | |
public bool IsReadOnly { get; set; } | |
public string DataTypeName { get; set; } | |
public string Placeholder { get; set; } | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict' | |
//represents .NET model metadata entry | |
var Meta = function(data) { | |
data = data || {} | |
var me = this | |
me.name = data.propertyName || "" | |
me.displayname = data.displayName || "" | |
me.type = data.dataTypeName || "" | |
me.isrequired = data.isRequired || false | |
me.isreadonly = data.isReadOnly || false | |
me.placeholder = data.placeholder || "" | |
} | |
//metadata deserealizer, see manageuser.js for usage | |
export var metadata = function(meta) { | |
let me = [] | |
if (meta) { | |
for (let d of meta) { | |
me.push(new Meta(d)) | |
} | |
} | |
return me | |
} | |
//label tag helper | |
//name is a string name of property in model | |
//model - is an m.prop of table record (User object), should contain 'meta' property with table metadata description | |
export var labelfor = function(name, model) { | |
if (model && typeof(model) == "function" && model().meta) { | |
for (let me of model().meta()) { | |
if (me.name.toLowerCase() === name.toLowerCase()) | |
return m('label', {"for": "#"+name}, (me.displayname) ? me.displayname : name) | |
} | |
} | |
return m('label', {"for": "#"+name}, name) | |
} | |
//<input> tag helper, name represents model's property name, ex: "email" | |
//model is an m.prop(object, ex: User, see manageuser.js) | |
//meta property represents .NET viewmodel metadata, see manageuser.js & ManageUserModel.cs + ApiModel.cs | |
export var inputfor = function(name, model) { | |
if (model && typeof(model) == "function" && model().meta) { | |
for (let me of model().meta()) { | |
if (me.name.toLowerCase() === name.toLowerCase()) | |
return m('input.form-control', { | |
id: name, | |
onchange: (me.isreadonly) ? null : m.withAttr("value", model()[name]), | |
value: model()[name](), | |
disabled: me.isreadonly, | |
required: me.isrequired, | |
type: inputtype(me) | |
}) | |
} | |
} | |
return m('input.form-control', {id: name}) | |
} | |
//return type for <input> tag, depending on .NET model's property data annotation (DataType(...)) | |
function inputtype(me) { | |
switch(me.type) { | |
case "EmailAddress": | |
return "email" | |
case "Date": | |
return "date" | |
case "Password": | |
return "password" | |
default: | |
return '' | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict' | |
import {metadata, labelfor, inputfor} from "./helpers" | |
//user object | |
var User = function(data){ | |
data = data || {} | |
this.email = m.prop(data.email|| '') | |
this.birthdate = m.prop(data.birthDate || '') | |
this.firstname = m.prop(data.firstName || '') | |
//.....// | |
this.meta = m.prop(metadata(data.meta)) | |
} | |
export var ManageUser = {} | |
ManageUser.vm = {} | |
ManageUser.vm.init = function() { | |
this.record = m.request({ method: "GET", url: "/api/manageuser", type: User }) | |
return this | |
} | |
ManageUser.controller = function () { | |
var ctrl = this | |
ctrl.vm = ManageUser.vm.init() | |
//.....// | |
} | |
ManageUser.view = function (ctrl) { | |
return m("#manageuser", [ | |
m('form.animated.fadeIn', [ | |
m('.row', [ | |
m('.form-group.col-md-4', [ | |
labelfor('email', ctrl.vm.record), | |
inputfor('email', ctrl.vm.record) | |
]), | |
m('.form-group.col-md-4', [ | |
labelfor('birthdate', ctrl.vm.record), | |
inputfor('birthdate', ctrl.vm.record) | |
]), | |
m('.form-group.col-md-4', [ | |
labelfor('firstname', ctrl.vm.record), | |
inputfor('firstname', ctrl.vm.record) | |
]), | |
]), | |
]) | |
]) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using Catalog.Models; | |
using Microsoft.AspNetCore.Authorization; | |
using Microsoft.AspNetCore.Identity; | |
using Microsoft.AspNetCore.Mvc; | |
using System.Threading.Tasks; | |
namespace Catalog.Controllers | |
{ | |
[Route("api/[controller]")] | |
[Authorize] | |
public class ManageUserController : Controller | |
{ | |
private readonly UserManager<ApplicationUser> _userManager; | |
public ManageUserController(UserManager<ApplicationUser> userManager) | |
{ | |
_userManager = userManager; | |
} | |
[HttpGet] | |
public async Task<IActionResult> Get() | |
{ | |
var user = await _userManager.GetUserAsync(HttpContext.User); | |
var model = new ManageUserModel(MetadataProvider) | |
{ | |
Email = user.Email, | |
FirstName = user.FirstName, | |
BirthDate = user.BirthDate, | |
//...........// | |
}; | |
return new ObjectResult(model); | |
} | |
[HttpPut] | |
//[ValidateAntiForgeryToken] //I'm still working on CSRF ajax validation ;) | |
public async Task<IActionResult> Update([FromBody] ManageUserModel model) | |
{ | |
if (ModelState.IsValid) | |
{ | |
var user = await _userManager.GetUserAsync(HttpContext.User); | |
if (user == null) | |
return NotFound(); | |
user.Email = model.Email; | |
user.FirstName = model.FirstName; | |
user.BirthDate = model.BirthDate; | |
//.......// | |
var result = await _userManager.UpdateAsync(user); | |
if (result.Succeeded) | |
{ | |
return new NoContentResult(); | |
} | |
AddErrors(result); | |
} | |
return new BadRequestObjectResult(ModelState); | |
} | |
#region Helpers | |
private void AddErrors(IdentityResult result) | |
{ | |
foreach (var error in result.Errors) | |
{ | |
ModelState.AddModelError(string.Empty, error.Description); | |
} | |
} | |
#endregion | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using Microsoft.AspNetCore.Mvc.ModelBinding; | |
using System; | |
using System.ComponentModel.DataAnnotations; | |
namespace Catalog.Models | |
{ | |
public class ManageUserModel : ApiModel | |
{ | |
public ManageUserModel(IModelMetadataProvider MetadataProvider) : base(MetadataProvider, typeof(ManageUserModel)) | |
{ | |
} | |
[Required] | |
[EmailAddress] | |
[Display(Name = "Email address")] | |
[Editable(false)] | |
public string Email { get; set; } | |
[Required] | |
[Display(Name = "First Name")] | |
[MaxLength(50, ErrorMessage = "{0} can't exceed 50 characters")] | |
public string FirstName { get; set; } | |
[Display(Name = "Date of Birth")] | |
[DataType(DataType.Date)] | |
public DateTime? BirthDate { get; set; } | |
//.........// | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment