Skip to content

Instantly share code, notes, and snippets.

@tabula-rasa
Created October 20, 2016 22:04
Show Gist options
  • Save tabula-rasa/c1d53131b940953efdf661b012ddd130 to your computer and use it in GitHub Desktop.
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)
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; }
}
}
'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 ''
}
}
'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)
]),
]),
])
])
}
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
}
}
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