@{
Layout = null;
}
@Html.DisplayNameFor(model => model.Provider) |
... More headers ...
@foreach (var item in Model) {
@Html.DisplayFor(modelItem => item.Provider) |
... More Row Data ...
}
```
]
???
- Layout = null tells Razor not to add Busey Logo header and copyright footer so we can include it in another page.
- @ sign invokes CSharp code.
- We did our data fetching and number crunching in the controller.
---
# _PartialTable.cshtml
![Rate Table Parial](img/webcon2016/ratepartial.png)
???
- What you get looks something like this.
- But you can change it now.
- For example, we added CSS for Bold first row.
---
# Include _PartialTable.cshtml in another page.
Assuming the ratepartial is served at /Home/_RateTable, we can embed it in another page with:
```Razor
@Html.RenderAction("_RateTable", "Home")
```
And then refresh it on the client side later with:
```JavaScript
$.ajax({
url: "/Home/_RateTable"
method: "GET",
contentType: 'application/json',
success: function (data, status, xhr) {
$("#rateList").html(data);
}
});
```
???
- id allows jQuery to find it.
- First part does the server side render.
- Second part allows client side updates without reloading the entire page.
---
# Razor Edit Form
???
- Visual Studio can generate a decent Edit Partial with Bootstrap already included.
---
# Razor Edit Form - Generated View Code
```CSharp
@model RateCompareWeb.ViewModels.RateViewModel
@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
}
@Html.ActionLink("Back to List", "Index")
```
???
About the generated Razor form
- class="col-md-10" - Bootstrap responsive column hints are included by default.
- ValidationSummary / ValidationMessageFor - Microsoft Unobtrusive Validation (Open Source JavaScript library for client side validation) is included by default.
- LabelFor - Gets text from the Display attribute from the ViewModel. Does not presently add ARIA accessibilty markup, but you can do so by hand in the htmlAttributes.
- submit - You get a normal submit buton. Unobtrusive has attached it's validation events for field.blur() and form.submit()
- You may want to use AJAX to POST the form. You can. It works fine.
- You can mix freeform HTML in with Razor as needed. It works fine.
---
# Razor Edit Form - Resulting HTML
```HTML
```
???
Quick Tour
- Razor creates HTML and JavaScript
- CSRF Token
- Title (Not Magic)
- Form groups contain input box and hidden validation message.
- Lots of data- markup.
- Activate some JavaScript.
- If you can write these data- attributes, Unobtrusive Validation with work with any server side technology (Django, Java, Ruby on Rails, Perl, PHP)
- You can write these data- attributes.
HIGHLIGHT THE UNOBTRUSIVE BEFORE SWITCHING SLIDES.
---
# Razor Edit Form
![Edit Form Parital](img/webcon2016/editrate.png)
???
- Notice the label text was not in the Razor. It is instead coming from the View Model.
- This lets you change a label in one place, the ViewModel, and have it update in all Add/Edit/List Razor views.
- String fields became input boxes.
- Boolean field became a checkbox.
- Do not try to implement 'By checking this box I agree...' at the ViewModel level.
- MVC requires false to be a valid option in any boolean field in the ViewModel.
- Microsoft's response to 'By checking this box I agree...' is "Stop that, it's silly."
- You will need to write a custom validator if you decide to do so anyway.
- Validation text appears automatically on field.blur and form.submit.
- Validation text also comes from the ViewModel attributes, for the same reason as display names do.
- You can change validation text in one place and have it apply to all forms.
---
# Unobtrusive Validation
???
- Unobtrusvie Validation happens at the browser...mostly.
- Clever JavaScript library reads HTML to do immediate validation.
- Razor reads Attributes on the ViewModel to add HTML that the JavaScript can read.
---
# Microsoft Unobtrusive Validation
- JavaScript
- [Open Source](https://github.com/aspnet/jquery-ajax-unobtrusive/blob/master/LICENSE.txt)
- [On GitHub](https://github.com/aspnet/jquery-ajax-unobtrusive)
- Useful without ASP.Net or Razor
- Declarative, like HTML5
???
- MVC automatically includes the JavaScript library for you.
- Razor generates the HTML markup for you.
- Like HTML5 - declares desired outcome, rather than steps.
- The JavaScript library is open source under the Apache 2 License
- Available in NuGet and Bower
- Try it with Django, Rails, WordPress, Drupal or Node.js
---
# Unobtrusive Validation Up Close
```HTML
```
???
- Unobtrusive Validaiton is Declarative
- JS library reads the data- attributes, and binds itself to the JS events (change, blur, submit)
- Razor can generate data-val-* or you can write it.
- Notice that we have three built-in validators here:
- required, length, regex
BUT HOW DID RAZOR DECIDE TO ADD THIS VALIDATION?
---
# Validation Attribute
```CSharp
public class PaymentViewModel {
[Display(Name = "Payment Amount")]
[DisplayFormat(
ApplyFormatInEditMode = true,
DataFormatString = "{0:F2}")]
[DataType(DataType.Currency)]
[Required(ErrorMessage = "Please supply a {0}.")]
public decimal Amount { get; set; }
// ...
}
```
???
- This is just one data field.
- Typically validation is applied both client and server side, but there are exceptions.
---
# Unobtrusive Validation - Custom jQuery Validator
Unobtrusive validators are built on jQuery validation.
```JavaScript
$.validator.addMethod("validatezipcode",
function (value, element, param) {
if (!(new RegExp(/^\d{5}(-?\d{4})?$/)).test(value)) {
return false;
}
return true;
}
);
jQuery.validator.unobtrusive.adapters.addBool("validatezipcode");
```
```HTML
```
???
- Sometimes we need a custom client side validator.
- Notice that once the validator is created, we apply it using an HTML attribute.
---
# Using Unobtrusive with React.js and other Dynamic Page Content
```JavaScript
$.validator.unobtrusive.parse("#EditForm");
```
???
- Unobtrusive will parse the page once when the library loads.
- If scripts dynamically add or remove data-val-* attributes, use this snippet after.
- Note that React.JS continuously rewrites the page to save memory.
- You may need this snippet in .render for certain React.JS components that use unobtrusive validation.
---
# React.js JSX - Client Side Render
???
- Browser gets JSON
- JavaScript library converts JSON into HTML
- Great for small page updates.
- Bad for first page load.
- Browser sends GET request
- Gets JSON data
- Gets JSX markup
- Gets JavaScript library React.js
- Uses JavaScript to generate HTML
- Renders the HTML
- Why not respond with HTML for the first request then?
---
# ReactJs.Net JSX - Server Side Pre-Render
???
- ReactJS.***Net*** is primarily a server side JSX rendering library.
- ReactJS.Net pre-renders the ViewModel into HTML on the server
- ...following the JSX rules.
---
# React.js Example - 1
JSX
```JSX
var ActionList = React.createClass({
getInitialState: function() {
return {actions: []};
},
render: function()
{
actions = this.state.actions.map(function (item) {
return (
);
}.bind(this));
return (
{this.props.title} |
{actions}
);
}
});
```
???
Cool stuff
- React components can be Composed of other React components.
- props are set in the HTML attributes
- state is set at runtime
Weird stuff
- Put each JSX file into both ReactConfig.cs and BundleConfig.cs
- ReactConfig.cs to allow ReactJS.Net to server side pre-render for speed.
- BundleConfig.cs to allow MVC to minify the React.JS JavaScript in production.
- Use className instead of class
- .bind(this) to call setState on the outer object.
- ReactJS.Net will call render and getInitialState sever side.
- Keep render and getInitialState as empty as you can.
---
# React.js Example - 2
HTML
```HTML
Do These Today
```
JSX
```JS
React.render(
,document.getElementById('todayActions')
);
```
???
- Just for completeness.
- This did not fit on the previous slide.
---
# Alternative to JSX
Reload a server side Razor partial using JQuery.
```JavaScript
$.get("/PropertyManager/_PropertyList", function (html) {
$("#PropertyList").html(html);
}
```
???
- Rendering stays server side.
- Still avoids full page reload.
- Still works with Single Page App
- Eliminates the need to alternate between Razor and JSX for form layout.
- No surprises during Server side pre-render, as with JSX.
- Benefits fully from ViewModel Attributes and ViewBag
---
# Conclusions
- We can build common needs fast in ASP.Net MVC.
- React.js integration with MVC is good.
- Razor Partials can replace many React.js use cases.
- jQuery Unobtrusive Validation is terrific.
???
# Conclusion notes
- I like these things. You may also.
---
# Microsoft Resources
- [Microsoft Resources for SPA](http://www.asp.net/single-page-application)
- [ASP.Net](http://www.asp.net/web-pages) [which is Open Source](https://github.com/aspnet)
- [NuGet Gallery](https://www.nuget.org/packages)
- [Model View Controller](http://www.asp.net/mvc)
- [MVVM Pattern](https://msdn.microsoft.com/en-us/library/hh848246.aspx)
- [LINQ](https://msdn.microsoft.com/en-us/library/bb397926.aspx)
- [Entity Framework](http://www.asp.net/entity-framework)
# JavaScript Resources
- [JQuery Validation](https://github.com/jzaefferer/jquery-validation/)
- [Unobtrusive Validation](https://github.com/aspnet/jquery-ajax-unobtrusive)
- [JavaScript Slide Deck with ReMark](https://gnab.github.io/remark)
- Background images created with [Aza Raskin's Algorithm Ink](http://azarask.in/projects/algorithm-ink/#b32debe8)
???
- Links here to more reading, if you are interested.
(Skip for time)
- We did not cover NuGet, LINQ, Entity Framework.
- NuGet is a package manager.
- Linq is a query builder language that works with Entity Framework and other data stores.
- We would typically use these with MVC.
---
# Questions?
- edward.delaporte@busey.com
- zach.carrington@busey.com
???
- You can find this slide deck at Edward.Delaporte.us
---
# Bonus Recipe: JavaScript Object Pattern
```JavaScript
var AddressHelper = {
FormId: "AddressForm",
ListId: "AddressList",
add: function() {
$.post("/api/property", function(data) {
$("#" + AddressHelper.ListId).html(data);
} )
},
setup: function () {
$("#" + AddressHelper.FormId).on("submit", AddressHelper.add);
}
}
AddressHelper.setup();
```
???
- Most JavaScript patterns suck.
- React.js uses JavaScript object pattern.
- JavaScript object pattern is the one easy win for using React.js.
- But you can use JavaScript Object pattern without React.js
- Globals are bad, except when they are well named, and used only on a page or two.
- This looks a lot like a React component, but is just a JavaScript object.
- This JavaScript object knows things, and can do things.
- Since it is JavaScript, it is also very flexible.
- You could replace the FormId or ListId or even the functions in realtime, if needed.
---
# Bonus Recipe: Submit Form with AJAX
???
- Razor drops out.
- Controller returns JSON instead of HTML
---
# Bonus Recipe: Submit Form with AJAX
```JavaScript
$("#editForm").on("submit", function (event) {
// Prevent full page HTTP submit.
if(event) event.preventDefault();
// Gather field data.
fields = {};
$("#editFormId").find("input[type=text],input[type=hidden]").map(function (id, item) {
fields[item.id] = item.value;
});
// ... Do clever user-friendly things here...
// Submit AJAX POST
$.post("api/thing/", fields, function ( post_response, status ) {
$("#result").html(post_response);
// ... Do more clever user-friendly things here...
});
});
````
???
(Skip for time.)
- Bind to JavaScript submit event - captures submit button, Enter key, other JavaScript posting the form.
- Prevent page reload.
- Test in Firefox - it works, but it can be sensitive.
- jQuery .find to find fields.
- jQuery .map to update dictionary for each field.
- jQuery .post to submit the form.
- jQuery .html to paste the response HTML right into our output status field.
- Whole update without a page reload.
- Clever things such as showing and hiding a spinner.
# Bonus Warning: Be Aware of MVC JavaScript Bundling
In App_Start/BundleConfig.cs
```CSharp
public static void RegisterBundles(BundleCollection bundles) {
bundles.Add(new ScriptBundle("~/bundles/jquery").Include(
"~/Scripts/jquery-{version}.js",
"~/Scripts/jquery-ui-{version}.js"));
}
```
In Views/Shared/_Layout.cshtml
```Razor
@Scripts.Render("~/bundles/jquery")
```
???
Notice
- JavaScript Bundles are minified when the debug flag is removed from web.config.
- Visual Studio removes debug from web.config when you publish in Release configuration.
- Bundle has no extension
Tips
- Use more than one bundle.
- Organize your bundles by types of pages you want to serve them on.
- User authorization level (i.e. public, registered, admin)
may be a good starting point for dividing up your JavaScript bundles.