Model –View-Controller (MVC)



User Interface Coding ToolsBackground Check SystemIT Technical Design GuideVersion 01 SAVEDATE \@ "M/d/yyyy" \* MERGEFORMAT 2/19/2015Table of Contents TOC \o "1-2" \u 1Model –View-Controller (MVC) PAGEREF _Toc411930945 \h 31.1MVC Solution Structure PAGEREF _Toc411930946 \h 31.2Bcs.Web.Mvc.Website.Bureaucrat PAGEREF _Toc411930947 \h 42jQuery and Knockout.js PAGEREF _Toc411930948 \h 42.1Knockout PAGEREF _Toc411930949 \h 52.2Knockout Mapping Plugin PAGEREF _Toc411930950 \h 72.3Knockout-delegatedEvents Plugin PAGEREF _Toc411930951 \h 83AjaxPostUtils.js PAGEREF _Toc411930952 \h 94Json Results Properties PAGEREF _Toc411930953 \h 104.1IsSuccessful PAGEREF _Toc411930954 \h 104.2ErrorMessages and ErrorMessage PAGEREF _Toc411930955 \h 104.3RedirectUrl PAGEREF _Toc411930956 \h 115Script Minification and Combining PAGEREF _Toc411930957 \h 116Bcs.Web.Mvc.Website.Bureaucrat.Controllers PAGEREF _Toc411930958 \h 127CSS and Branding PAGEREF _Toc411930959 \h 12Model –View-Controller (MVC)The Background Check System (BCS) website is a model-view-controller (MVC) version 3 application. The application uses the Razor View Engine to render client views. For Visual Studio 2010, MVC 3 is an add-on found here: . Visual Studio 2012 and above include support for MVC 3 and later versions.MVC Solution StructureThe core of the website application consists of three projects:Bcs.Web.Mvc.Website.Bureaucrat, highlighted in blue above, contains the Content and MVC Views. This is the project that gets published. Bcs.Web.Mvc.Website.Bureaucrat.Controllers, highlighted just below in yellow, contains the MVC Controllers. Bcs.Web.Mvc.Website.Bureaucrat.Models contains the view model classes. The .Cjis projects include Controllers and Model classes used with CJIS encryption, described in the “Database and Application Deployment” IT guide. Cjis Views are included in a Cjis folder in the main Bcs.Web.Mvc.Website.Bureaucrat project.Bcs.Web.Mvc.Website.BureaucratOne thing to note about the organization of Views in this project is that they are contained in folders with Views, and subfolders for Partials and Dialogs as show below.This folder separation of Partials and Dialogs Views is provided by a custom MVC ViewEngine (FindViewsViewEngine). The sole purpose of this ViewEngine subclass is to resolve MVC View search by including the Dialogs and Partials path in the search paths.jQuery and Knockout.jsMuch of the functionality in this website project is provided by jQuery and Knockout. In addition, jQuery-UI is used for dialogs and tabbed views. As of this writing, the version of jQuery used in the BCS is 1.11.1, jQuery-UI is 1.11.0, and Knockout is 3.2.0. Knockout.js was shipped with Visual Studio 2012, and is also available at and via Nuget.The BCS uses two additional plug-ins for Knockout. Knockout-mapping-latest.js is used to map view model properties into Knockout observables. The knockout-delegatedEvents.js plug-in by Ryan Niemeyer enables simple delegated event handling in Knockout views.KnockoutKnockout.js is a JavaScript two-way binding library that the BCS uses primarily for user interface grids. The normal pattern is for the data from a C# class view model to be written to the MVC View. This data is then mapped by the Knockout mapping plug-in into a JavaScript object. This JavaScript object is then bound to an HTML <div> /<table> pair.var DeterminationHiringDecisionModel = function () {var self = this;// Other functionality}var vm = new DeterminationHiringDecisionModel();ko.mapping.fromJS(@Html.Raw(Json.Encode(Model)), '', vm);Finally, inside the jQuery document ready function, the JavaScript object is bound to the appropriate HTML element.ko.applyBindings(vm, document.getElementById('fsDHDResults'));An example of a grid (where this grid <div> would be inside the HTML element where the Knockout view model was bound):<div class="grid" data-bind="visible: DeterminationHiringDecisionResults().length > 0"><table id="applicationsTbl" class="sortableGrid" summary="List of Determination Hiring Decisions Results"><caption>Determination Hiring Decision Search Results</caption><thead><tr><th class="nosort">Locked</th><th class="ApplicationId" scope="col">App #</th><th class="ProviderName" scope="col" style="max-width: 16em;">Provider</th><th class="LastName" scope="col">Last</th><th class="FirstName" scope="col">First</th><th class="SsnLastFour" scope="col">SSN</th><th class="nosort" scope="col">Employment<br />Status</th><th class="nosort" scope="col" style="text-align: center;">Action</th></tr></thead><tbody data-bind="foreach: DeterminationHiringDecisionResults, delegatedHandler: 'click'"><tr><td><span class="lockDetail ui-icon ui-icon-locked" data-bind="visible: IsLocked(), attr:{title: 'Record is being edited by another User'}"></span></td><td class="max6" data-bind="text: ApplicationId"></td><td style="white-space: normal"><span class="link" data-click="viewProvider" data-bind="text: ProviderName"></span></td><td class="max10" class="elipflow"><a class="viewPersonSummary link" data-bind="attr: {title: 'view ' + FirstName() + ' ' + LastName() + ' Person Summary'}, text: LastName"></a></td><td data-bind="text: FirstName" class="max5 elipflow"></td><td style="white-space: nowrap" data-bind="ssn: Ssn"></td><td data-bind="template:{name:'EmploymentStatusTemplate'}"></td><td data-bind="template:{name:'ActionsTemplate'}"></td></tr></tbody></table>@{ Html.RenderPartial("Paging", Model.DeterminationHiringDecisionResults); }</div>The ‘data-bind’ attributes tell Knockout what actions to take and what properties to bind. The data-bind="visible: DeterminationHiringDecisionResults().length > 0” attribute on the grid <div> tells Knockout to only show this grid when there are DeterminationHiringDecisionResults. The DeterminationHiringDecisionResults array is a Knockout observable, thus if there happens to be only one result (one grid row) and that row is removed (by a ‘hiring’ action), the grid <div> will be hidden.The data-bind ‘foreach’ attribute on the table body element (<tbody data-bind="foreach: DeterminationHiringDecisionResults, delegatedHandler: 'click’”>) tells Knockout to iterate through the DeterminationHiringDecisionResults array creating table rows from the <tr> template inside the table body element. Most of the time, view model properties are displayed in grids with the ‘text’ binding, like:<td class="max6" data-bind="text: ApplicationId"></td>The Knockout text binding outputs the property as text. Occasionally grids need to output a property as HTML and use the Knockout HTML binding. In this case, the Address has been formatted with <br> tags which need to be honored in the resulting display:<td class="max10" data-bind="html: Address"></td>The BCS also uses a custom ‘yesno’ binding. This binding outputs a bool or nullable bool as either ‘Yes’, ‘No’, or blank if null.<td data-bind="yesno: CanSubmitElectronically”></td>The custom ‘date’ binding outputs a date formatted as mm/dd/yyyy, while the ‘datetime’ binding also appends the time to the date. There is also a custom SSN binding that prepends a hyphen to a 4 character SSN and outputs as is a full SSN.Knockout Mapping PluginThe Knockout mapping plugin (knockout-mapping-lastest.js) by default maps all fields in a data model into Knockout observables. This is simple, fast, and works well for our multi-page application. There are occasions when we want to augment the resulting mapped object with observables or properties without needing to include these properties in the original C# data model. In the following snippet, we add 3 observables to each Payment object as it is mapped:In these cases, this mapping variable replaces the default empty string in the ko.mapping.fromJS function:Knockout-delegatedEvents PluginThe knockout-delegatedEvents plugin (knockout-delegatedEvents.js) provides a simple unobtrusive mechanism for hooking up ‘click’ and ‘change’ events. To use knockout-delegatedEvents, include the events you intend to catch in a Knockout data-bind attribute. The scope of this data bound element must include the elements for which you are intending to catch events. It is typical to include a delegated events data-bind attribute on some top-level <div> or fieldset element:<fieldset id="fsAppeals" data-bind="delegatedHandler: ‘click’">Or when you need to catch both ‘click’ and ‘change’ events:<fieldset id="fsInfo" data-bind="delegatedHandler: ['click', 'change']">With this in place, adding a ‘data-click’ attribute on a button will cause the referenced function on a view model to be invoked when the button is clicked:<button data-click="AutoExtend">Extend Appeal Date</button>The delegated events plugin helpfully includes a reference to both the data item (usually the array element represented on the grid row) and the JavaScript event variable in the parameters to the view model function.AjaxPostUtils.jsAlthough most JavaScript is currently on-page JavaScript, Ajax functionality is contained in AjaxPostUtils.js. This script provides several functions that are used throughout the BCS MVC application.Pages with search filters (Determination in Process, Ready for Determination, Not Yet Submitted, etc.) use Ajax posts with callbacks (which could be easily changed to Promises) to avoid refreshing the whole page when a changed filter criteria is applied. The typical search page posts the filter criteria and supplies a <div> tag selector where the resulting PartialView should be rendered.iaApp.PostFormForPartial(<mvc route>, <form id>, <selector>);This action is often encapsulated in the helper function searchPartialHelper.setup (in bindings.helper.js), which observes the Search button and automatically generates the search request (using iaApp.PostFormForPartial) and places the resulting PartialView in the tag referenced in the passed jQuery selector. When used like this, Search buttons should include a CSS class of ‘gridRefresher’.A similar function in AjaxPostUtil is iaApp.PostFormWithSuccessHandler. This function posts a form, but the callback is only executed if successful. Validation errors will be automatically appended to the form’s validation message area and will not result in executing the passed callback. This iaApp.PostFormWithSuccessHandler function is often used to post dialog form data.The example below is typical of displaying a dialog and then posting the dialog form with iaApp.PostFormWithSuccessHandler. The ReviewExtensionRequestion function is called when a user clicks the ‘Review Extension’ on a grid row. The function posts the AppealId to the controller, which renders a partial view (the dialog). The partial view is written into the page in the extensionEditor <div>, then the dialog is opened (bcsdlgs.Open). When the user clicks ‘Save’ on the dialog, the SaveApproval function is called (shown below). SaveApproval uses iaApp.PostFormwithSuccessHandler to post the form to the controller. Any validation errors will be displayed and the callback not executed. A successful save executes the callback, which maps the return data to a Knockout object, and then replaces the existing row (saved temporarily in self.activeItem) with this replacement object.Json Results PropertiesIsSuccessfulBCS JSON results generally return the property IsSuccessful. Looking at this flag, for example, is how the iaApp.PostFormWithSuccessHandler determines whether to call the callback function.ErrorMessages and ErrorMessageWhen IsSuccessful is false, BCS JSON includes an array of error messages. This array is used by iaApp.PostFormWithSuccessHandler to render validation messages. When there is no form involved but there are error messages provided by the MVC Controller action, this array is concatenated into ErrorMessage. This message is often displayed in these cases by calling iaApp.DisplayErrorMessage. This call displays the message in a warning area below the main navigation menu.RedirectUrlSome JSON results also include a RedirectUrl property. This is the URL for redirecting the browser. An Ajax post to start an appeal, for example, might return IsSuccessful = true, and a RedirectUrl to the appeals in process page with a query string to automatically select this new appeal.Script Minification and CombiningScripts are minified and combined using the Microsoft Ajax Minifier (). The build directives are specified in the Bureaucrat.ajaxmin file in the web project Build folder:Bcs.Web.Mvc.Website.Bureaucrat.ControllersThis project contains all of the MVC Controllers except for one Cjis encryption-specific controller (OffensesController), which is in a separate project (Bcs.Web.Mvc.Website.Bureaucrat.Controllers.Cjis), and a Dev/debugging controller in Bcs.Web.Mvc.Website.Bureaucrat.Controllers.Dev.The simplest flow from database to screen is: db -> DTO -> Controller view model -> JSON -> Knockout client view model. DTOs are never rendered directly to views. (These controller view models are contained in the Bcs.Web.Mvc.Website.Bureaucrat.Models project.)In addition to simple DTOs that typically represent a single table, the BCS makes significant use of custom DTOs (found in Dto/Custom folders in the appropriate middle-end module project). The PersonProfile custom DTO contains fields from Person, Address, PersonAddress, and Alias.MVC Controller actions that load Views (for example, a request for a partial view representing a grid) typically call a middle-end search, which returns an IList of a search result DTO. These DTOs are converted in view models and rendered to the Razor View. Much of this conversion effort is kept out of the Controller code and instead handled by convenient constructor methods on the view models that take a search result DTO as a parameter. These DTO-specific view model constructions often take advantage of additional parameters that reflect the user’s Permissions.This conversion of a list (in this case an IPagedList) of ReadyForDeterminationSearchResult custom DTOs is typical:IPagedList<ReadyForDeterminationModel> readyForDeterminations =searchResults.ToConvertedList<ReadyForDeterminationSearchResult,ReadyForDeterminationModel, bool, bool>(SessionState.UserInfo.HasPermission(Permission.EDIT_CRIMINAL_HISTORY_DETERMINATION),SessionState.UserInfo.HasPermission(Permission.REGISTRY_RESEARCH),CSS and BrandingThe primary CSS files are in Content > Common >Styles folder. These primary files (Theme.css and jquery-ui.css) contain the bulk of the styles. CSS in these files can be augmented or overridden by the Theme.css in the appropriate Content> [dept code] > Styles folder.The banner branding for the site is contained in a department Views folder: Views > _Departments > [dept code] > Partials/BrandingHead.cshtml. ................
................

In order to avoid copyright disputes, this page is only a partial summary.

Google Online Preview   Download