Skip to content
This repository was archived by the owner on Dec 14, 2018. It is now read-only.

Add TagHelperSample.Web #1289

Merged
merged 2 commits into from
Oct 10, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions Mvc.sln
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "RazorInstrumentationWebSite
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "ApplicationModelWebSite", "test\WebSites\ApplicationModelWebSite\ApplicationModelWebSite.kproj", "{CAE52CB7-0FAC-4B5B-8251-B0FF837DB657}"
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "TagHelperSample.Web", "samples\TagHelperSample.Web\TagHelperSample.Web.kproj", "{2223120F-D675-40DA-8CD8-11DC14A0B2C7}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -482,6 +484,16 @@ Global
{6DB9B8D0-80F7-4E70-BBB0-0B4C04D79A47}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{6DB9B8D0-80F7-4E70-BBB0-0B4C04D79A47}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{6DB9B8D0-80F7-4E70-BBB0-0B4C04D79A47}.Release|x86.ActiveCfg = Release|Any CPU
{2223120F-D675-40DA-8CD8-11DC14A0B2C7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2223120F-D675-40DA-8CD8-11DC14A0B2C7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2223120F-D675-40DA-8CD8-11DC14A0B2C7}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{2223120F-D675-40DA-8CD8-11DC14A0B2C7}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{2223120F-D675-40DA-8CD8-11DC14A0B2C7}.Debug|x86.ActiveCfg = Debug|Any CPU
{2223120F-D675-40DA-8CD8-11DC14A0B2C7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2223120F-D675-40DA-8CD8-11DC14A0B2C7}.Release|Any CPU.Build.0 = Release|Any CPU
{2223120F-D675-40DA-8CD8-11DC14A0B2C7}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{2223120F-D675-40DA-8CD8-11DC14A0B2C7}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{2223120F-D675-40DA-8CD8-11DC14A0B2C7}.Release|x86.ActiveCfg = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -526,5 +538,6 @@ Global
{2B2B9876-903C-4065-8D62-2EE832BBA106} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
{CAE52CB7-0FAC-4B5B-8251-B0FF837DB657} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
{6DB9B8D0-80F7-4E70-BBB0-0B4C04D79A47} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
{2223120F-D675-40DA-8CD8-11DC14A0B2C7} = {DAAE4C74-D06F-4874-A166-33305D2643CE}
EndGlobalSection
EndGlobal
75 changes: 75 additions & 0 deletions samples/TagHelperSample.Web/Controllers/HomeController.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@

using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNet.Mvc;
using Microsoft.AspNet.Mvc.Rendering;
using TagHelperSample.Web.Models;

namespace TagHelperSample.Web.Controllers
{
public class HomeController : Controller
{
private static readonly IEnumerable<SelectListItem> _items = new SelectList(Enumerable.Range(7, 13));
private static readonly Dictionary<int, User> _users = new Dictionary<int, User>();
private static int _next;

public HomeController()
{
// Unable to set ViewBag from constructor. Does this work in MVC 5.2?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's set via the DefaultControllerActivator from an [Activate] attribute which is why it doesn't work today (activates the controller after it's been instantiated).

Does work in 5.2 though.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will track as a straight-up MVC 6.0 bug that this NREs

////ViewBag.Items = _items;
}

// GET: /<controller>/
public IActionResult Index()
{
return View(_users.Values);
}

// GET: /Home/Create
public IActionResult Create()
{
ViewBag.Items = _items;
return View();
}

// POST: Home/Create
[HttpPost]
public IActionResult Create(User user)
{
if (user != null && ModelState.IsValid)
{
var id = _next++;
user.Id = id;
_users[id] = user;
return RedirectToAction("Index");
}

ViewBag.Items = _items;
return View();
}

// GET: /Home/Edit/5
public IActionResult Edit(int id)
{
User user;
_users.TryGetValue(id, out user);

ViewBag.Items = _items;
return View(user);
}

// POST: Home/Edit/5
[HttpPost]
public IActionResult Edit(int id, User user)
{
if (user != null && id == user.Id && _users.ContainsKey(id) && ModelState.IsValid)
{
_users[id] = user;
return RedirectToAction("Index");
}

ViewBag.Items = _items;
return View();
}
}
}
18 changes: 18 additions & 0 deletions samples/TagHelperSample.Web/Models/User.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@

using System;

namespace TagHelperSample.Web.Models
{
public class User
{
public int Id { get; set; }

public string Name { get; set; }

public string Blurb { get; set; }

public DateTimeOffset DateOfBirth { get; set; }

public int YearsEmployeed { get; set; }
}
}
15 changes: 15 additions & 0 deletions samples/TagHelperSample.Web/Startup.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@

using Microsoft.AspNet.Builder;
using Microsoft.Framework.DependencyInjection;

namespace TagHelperSample.Web
{
public class Startup
{
public void Configure(IApplicationBuilder app)
{
app.UseServices(services => services.AddMvc());
app.UseMvc();
}
}
}
18 changes: 18 additions & 0 deletions samples/TagHelperSample.Web/TagHelperSample.Web.kproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
</PropertyGroup>
<Import Project="$(VSToolsPath)\AspNet\Microsoft.Web.AspNet.Props" Condition="'$(VSToolsPath)' != ''" />
<PropertyGroup Label="Globals">
<ProjectGuid>2223120f-d675-40da-8cd8-11dc14a0b2c7</ProjectGuid>
<OutputType>Web</OutputType>
<RootNamespace>TagHelperSample.Web</RootNamespace>
</PropertyGroup>
<PropertyGroup>
<SchemaVersion>2.0</SchemaVersion>
<DevelopmentServerPort>31726</DevelopmentServerPort>
</PropertyGroup>
<Import Project="$(VSToolsPath)\AspNet\Microsoft.Web.AspNet.targets" Condition="'$(VSToolsPath)' != ''" />
</Project>
89 changes: 89 additions & 0 deletions samples/TagHelperSample.Web/Views/Home/Create.cshtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@

@using TagHelperSample.Web.Models
@model User

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: Once the TagHelper project is created we'll have to add an @addtaghelper "theassembly" here for the TagHelpers on the page to light up. Or if we're able to get the _ViewStart support in we'll be able to add them there.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not actionable in this PR

<h2>Create</h2>

@* anti-forgery is on by default *@
@* form will special-case anything that looks like a URI i.e. contains a '/' or doesn't match an action *@
<form anti-forgery="false" action="Create">
<div class="form-horizontal">
@* validation summary tag helper will target just <div/> elements and append the list of errors *@
@* - i.e. this helper, like <select/> helper has ContentBehavior.Append *@
@* validation-model-errors-only="true" implies validation-summary="true" *@
@* helper does nothing if model is valid and (client-side validation is disabled or validation-model-errors-only="true") *@
@* don't need a bound attribute to match Html.ValidationSummary()'s headerTag parameter; users wrap message as they wish *@
@* initially at least, will not remove the <div/> if list isn't generated *@
@* - should helper remove the <div/> if list isn't generated? *@
@* - (Html.ValidationSummary returns empty string despite non-empty message parameter) *@
<div validation-summary="true" validation-model-errors-only="true">
<span style="color:red">This is my message</span>
</div>

@* element will have correct name and id attributes for Id property. unusual part is the constant value. *@
@* - the helper will _not_ override the user-specified "value" attribute *@
<input type="hidden" for="Id" value="0" />
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this file isn't much different from Edit.cshtml but I only use a user-specified HTML attributes (that helper would normally generate) here. suspect "class" attribute would be merged but all other user-specified HTML attributes would just win.


<div class="form-group">
@* no special-case for the "for" attribute; may eventually need to opt out on per-element basis here and in <form/> *@
<label for="Name" class="control-label col-md-2" style="color:blue" />
<div class="col-md-10">
<input type="text" for="Name" style="color:blue" />
<span validation-for="Name" style="color:blue" />
</div>
</div>
<div class="form-group">
<label for="DateOfBirth" class="control-label col-md-2" />
<div class="col-md-10">
@* will automatically infer type="date" (reused HTML attribute) and format="{0:d}" (optional bound attribute) *@
<input for="DateOfBirth" />
<span validation-for="DateOfBirth">How old are you?</span>
</div>
</div>
<div class="form-group">
<label for="YearsEmployeed" class="control-label col-md-2" />
<div class="col-md-10">
@* <select/> tag helper has ContentBehavior.Append -- items render after static options *@
<select for="YearsEmployeed" items="(IEnumerable<SelectListItem>)ViewBag.Items" size="2" class="form-control">
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"items" attribute needn't be so ugly. I just didn't switch from User to UserViewModel in this sample.

@* schedule-wise option tag helper (which adds "selected" attribute to static <option/>s) comes after helpers *@
@* - static use of "selected" attribute may cause HTML errors if in a single-selection <select/> *@
@* - @NTaylorMullen thinks <option/> tag helper could tell <select/> helper not to select anything from "items" *@
@* - wouldn't help if user selected one static <option/> and expression indicated another, especially one earlier in the <select/> *@
@* - may need a "default" bound parameter on the <select/> to avoid these cases and maintain "don't override" *@
<option value="" selected="selected">Why didn't you select anything?</option>
<optgroup label="Newby">
<option value="0">Less than 1</option>
<option value="1">1</option>
</optgroup>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
<option value="5">5</option>
<option value="6">6</option>
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note user should not specify selected="selected" because option tag helper won't remove that attribute. to do so would create an odd special case in the "user-specified HTML attributes win" rule.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

comments in Create.cshtml revise this thinking somewhat

</select>

@* targets only <span/> in Beta; does not support equivalent of Html.ValidationMessageFor()'s tag parameter *@
@* - may eventually either support additional tags e.g. <p/> and <div/> or all tags /> *@
<span validation-for="YearsEmployeed" />
</div>
</div>
<div class="form-group">
<label for="Blurb" class="control-label col-md-2" />
<div class="col-md-10">
<textarea rows="4" for="Blurb"></textarea>
<span validation-for="Blurb" />
</div>
</div>

<div class="form-group">
<div class="col-md-offset-2 col-md-10">
@* this <input/> lacks a "for" attribute and will not be changed by the <input/> tag helper *@
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
</form>

<div>
<a action="Index">Back to list</a>
</div>
61 changes: 61 additions & 0 deletions samples/TagHelperSample.Web/Views/Home/Edit.cshtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@

@using TagHelperSample.Web.Models
@model User

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: Once the TagHelper project is created we'll have to add an @addtaghelper "theassembly" here for the TagHelpers on the page to light up. Or if we're able to get the _ViewStart support in we'll be able to add them there.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not actionable in this PR

<h2>Edit</h2>

<form>
<div class="form-horizontal">
<div validation-summary="true"/>
<input type="hidden" for="Id" />

<div class="form-group">
<label for="Name" class="control-label col-md-2" />
<div class="col-md-10">
<input type="text" for="Name" />
<span validation-for="Name" />
</div>
</div>
<div class="form-group">
<label for="DateOfBirth" class="control-label col-md-2" />
<div class="col-md-10">
<input type="date" for="DateOfBirth" format="{0:d}" />
<span validation-for="DateOfBirth">How old are you?</span>
</div>
</div>
<div class="form-group">
<label for="YearsEmployeed" class="control-label col-md-2" />
<div class="col-md-10">
<select for="YearsEmployeed" items="(IEnumerable<SelectListItem>)ViewBag.Items" size="2" class="form-control">
<optgroup label="Newby">
<option value="0">Less than 1</option>
<option value="1">1</option>
</optgroup>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
<option value="5">5</option>
<option value="6">6</option>
</select>
<span validation-for="YearsEmployeed" />
</div>
</div>
<div class="form-group">
<label for="Blurb" class="control-label col-md-2" />
<div class="col-md-10">
<textarea rows="4" for="Blurb"></textarea>
<span validation-for="Blurb" />
</div>
</div>

<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</div>
</div>
</form>

<div>
<a action="Index">Back to list</a>
</div>
35 changes: 35 additions & 0 deletions samples/TagHelperSample.Web/Views/Home/Index.cshtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@

@using TagHelperSample.Web.Models
@model IEnumerable<User>

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: Once the TagHelper project is created we'll have to add an @addtaghelper "theassembly" here for the TagHelpers on the page to light up. Or if we're able to get the _ViewStart support in we'll be able to add them there.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not actionable in this PR

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we have an idea of the exact syntax it would be to add the built-in tag helpers? Or are those always present? Or?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Opt-in: @addtaghelper "Microsoft.AspNet.Mvc.TagHelpers"

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it, thanks!

<h2>Index</h2>
<p>
<a action="Create">Create New</a>
</p>

@if (Model != null && Model.Count() != 0)
{
<div class="form-horizontal">
@foreach (var item in Model)
{
<div class="form-group">
<label for="@item.Name" />
<input type="text" for="@item.Name" disabled="disabled" readonly="readonly" />

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: The current plan results in this not working until after beta. Might not be valuable to have until then since it'll just cause compile errors on the view.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👎 this sample is aspirational and uses lots of unimplemented features

</div>
<div class="form-group">
<label for="@item.DateOfBirth" />
<input type="date" for="@item.DateOfBirth" disabled="disabled" readonly="readonly" />
</div>
<div class="form-group">
<label for="@item.YearsEmployeed" />
<input type="number" for="@item.YearsEmployeed" disabled="disabled" readonly="readonly" />
</div>
<div class="form-group">
<label for="@item.Blurb" />
<textarea rows="4" for="@item.Blurb" disabled="disabled" readonly="readonly" />
</div>

<a action="Edit" controller="Home" route="MyRouteName" route-id="@item.Id">Edit</a>
}
</div>
}
24 changes: 24 additions & 0 deletions samples/TagHelperSample.Web/project.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"compilationOptions": {
"warningsAsErrors": true
},
"dependencies": {
"Microsoft.AspNet.Mvc": "6.0.0-*",
"Microsoft.AspNet.Server.IIS": "1.0.0-*",
"Microsoft.AspNet.Server.WebListener": "1.0.0-*",
"Microsoft.Framework.ConfigurationModel": "1.0.0-*"
},
"commands": {
"web": "Microsoft.AspNet.Hosting server=Microsoft.AspNet.Server.WebListener server.urls=http://localhost:5001"
},
"frameworks": {
"aspnet50": {
"dependencies": {
"Microsoft.Framework.ConfigurationModel.Json": "1.0.0-*"
}
},
"aspnetcore50": {
"dependencies": { }
}
}
}