One of the thing in my to-do list for MVC is "figure out how to do client-side validation". Isn't that supplied out of the box since like ASP.NET MVC 2? Yes, it is - but it only work out of the box if the form is not dynamically fetched.
In my projects, most of the form is a dynamic form - so user click an icon and then the form (empty or pre-filled) is fetched via AJAX and then displayed (some times in a jQuery dialog). This is a quite common scenario, for example: you are looking at your account profile screen and displayed there is a list of your phone numbers that you have registered. Let's say you then want to edit one of those since you changed your phone number. So you click the edit button/icon next to your phone number on the screen and a dialog box pops with the old phone number, you edit it, click "Save" and the list refreshes with your phone number.
To simply enforcing a "required" field validation in this scenario was quite complicated. Especially when your AJAX submit handler is a custom handler (instead of using the stock ASP.NET MVC AJAX Helper). But now, by adding less than 10 lines of code, add 2 lines of configuration settings in the web.config and including less than 3 javascripts - it is all possible!
-- read more and comment ...
Tuesday, April 19, 2011
Client-Side Validation with AJAX/Dynamic Form
By
Johannes Setiabudi
@
1:03 AM
0
comments! add yours!
Tuesday, March 29, 2011
jQuery update for IE9
When Internet Explorer was released, I downloaded it immediately and replaced my IE8. It works superbly except on a project that I was working on. For some reason, some javascripts are causing errors and won't work. I was using jQuery 1.4.x and jQuery UI 1.8.1.
After some investigation, the existence of the meta-tag to force IE compatibility and the outdated jQuery scripts were causing all the errors.
So I removed the meta-tag ("<meta http-equiv="x-ua-compatible" content="IE=8" />") and updated the jQuery reference to the latest greatest (1.5.1 and UI 1.8.11) - and all are happy again.
-- read more and comment ...
Friday, January 7, 2011
Microsoft Certification exams
My employer (AWH - http://www.awh.net) encourages us (the employees) to take MS certifications. Not only this will benefit the company in maintaining our status as a Gold Partner, but also will benefit us as far as knowledge, new technology, etc. Plus the certifications are attached to the individual, so if you change jobs, those certifications certainly belong in your resume and can be leveraging points.
AWH will pay for the tests, including first failure. So if I take a test and fail, and then retake the test and pass, AWH will cover both exams. So I have to pass before the reimbursement can come through.
Anyway, so last November, I saw a promotion on Prometric's website for a 2/3/4/5 exam packets with discounted price and FREE retakes for each exams in the packet. With that good deal in mind, I decided that I will set a goal in this area: getting a MCPD - Microsoft Certified Professional Developer. This certification requires 4 exams:
I took the first test early in December and passed it quite easily. Since ASP.NET is what I use daily, most of the questions in the test are familiar to me and I can answer them correctly.
I scheduled to take the ADO.NET test on Dec 23rd, but when I came to the facility, it was closed. I was not notified of any closing and Prometric also was not aware of the closing of the local facility (New Horizons). Prometric was able to reschedule me for Dec 27th at a different facility. I failed my ADO.NET test - probably by 2 or 3 questions, it was so close. Although I use ADO.NET stuff pretty much daily, but there are some things in there that are pretty new to me and I have not used them in production quality code - like Entity Framework. Those questions stumped me and resulting in a failing grade. Thank God for the free retake!
So I studied more EF, practice making some projects with with etc and retake the test on December 29th. I passed.
So next up is WCF - scheduled for Jan 12th. Hopefully by end of Feb 2011, I will have become an MCPD.
-- read more and comment ...
By
Johannes Setiabudi
@
12:34 PM
0
comments! add yours!
Wednesday, June 9, 2010
jQuery 1.4.x Ajax traditional option
I have a very simple jQuery code that basically sends an array of integer back to my ASP.NET MVC Controller class.
$.post ("/MyController/MyAction", { myArray: ids });
My controller action:
public void MyAction (int[] myArray) {
// do stuff here ...
}
But upon upgrading to jQuery 1.4.x, it does not work anymore. The param "myArray" in MyAction is always null.
After some readings, it turns out that this is a change in the jQuery 1.4 release - it changes the way it does param serialization. But, jQuery also provides a new flag in $.ajax to override the default behavior (and go back to use the old way of param serialization): the "traditional" option in $.ajax. So here is my revised code:
$.ajax({
type: 'POST',
url: "/MyController/MyAction",
data: { myArray: ids },
traditional: true
});
You can read more about the new param serialization here and here (under "Nested param serialization" section).
By
Johannes Setiabudi
@
4:30 PM
0
comments! add yours!
Wednesday, March 10, 2010
AJAX Animation using jQuery
During an AJAX call from a website, usually the screen won't blink - because page is not refreshing. This is neat because it gives the impression to the user that their interaction with the site to be seamless and uninterrupted.
But sometimes, you do want to give a visual clue to the user that an action is happening and you want them to know about it. Maybe by giving them an hourglass or a "loading ..." clue etc. So how do you do this easily? This post is about using jQuery to provide visual clue to the user on AJAX requests.
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js" type="text/javascript"></script>Add the HTML to display our visual clue. In this example I am displaying a black bar on the top of the browser, about 25px in height that has a "Loading ..." text in it. So when an AJAX call is happening, this black bar will be displayed until the call is done.
<div style="z-index:101; width:100%; height:25px; position:fixed; left:0px; top: 0px;"> <div id="loadingbar" style="height:25px;display:none; margin-left:auto; margin-right:auto; background-color:#000000; color:#fff"> Loading ...</div> <div class="stretch"> </div> </div>Now we add the javascript to show and hide the bar, plus I also like to gray out the background a little bit.
$(document).ready(function() {
jQuery().ajaxStart(function() {
$("body").fadeTo("fast", 0.70);
$("#loadingbar").show("fast");
});
jQuery().ajaxStop(function() {
$("body").fadeTo("fast", 1.0);
$("#loadingbar").hide("fast");
});
});
Done. Now anytime there is an AJAX call in your page, the background will be grayed out a little bit and a black bar will show up on the top. To increase/decrease the opacity of the background during the graying out, you can adjust the value on the "fadeTo" call. Currently it is set to "0.70" or 70%. If you want less transparency (or more grayed out), then set it lower (between 0.00 to 1.0), and set it higher for less transparency.
By
Johannes Setiabudi
@
9:55 PM
0
comments! add yours!
Friday, February 5, 2010
Implementing jQuery FullCalendar PlugIn with ASP.NET MVC
I have been using jQuery for most of my javascript work, so when I need to display a calendar related data in a "month view", I did a search for jQuery plug-ins that will work with my existing project (and extensible to be used for future projects as well). My current projects are built using ASP.NET MVC, so working with jQuery and its plug-ins just makes sense.
After a careful research, trial & error, I finally picked "FullCalendar" jQuery plug-in. You can download it here. It says in its website as:
"FullCalendar is a jQuery plugin that provides a full-sized, drag & drop calendar like the one below. It uses AJAX to fetch events on-the-fly for each month and is easily configured to use your own feed format (an extension is provided for Google Calendar). It is visually customizable and exposes hooks for user-triggered events (like clicking or dragging an event)"
$(document).ready(function() {
$('#calendar').fullCalendar();
}
Somewhere in the HTML:
<div id='calendar'></div>Set the controller code to display the view:
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult MonthView() {
return View();
}
At this point, we should be able to display the empty calendar by going to http://<site>/<controller_name>/MonthView.So now, we are going to modify this empty calendar to display the data from somewhere (db/xml/etc) via AJAX. For this, I created a class called "CalendarEvent" which structure is mimicking the JSON object model described in here; such as this:
public class CalendarEvent {
public string id { get; set; }
public string title { get; set; }
public string date { get; set; }
public string start { get; set; }
public string end { get; set; }
public string url { get; set; }
}
Then in the controller code:
[AcceptVerbs(HttpVerbs.Get)]
public JsonResult CalendarData() {
DateTime start = new DateTime(1970, 1, 1);
DateTime end = new DateTime(1970, 1, 1);
start = start.AddSeconds(double.Parse(Request["start"]));
end = end.AddSeconds(double.Parse(Request["end"]));
// call middle tier/orm/whatever to get data from source
List list = SearchForEvents(start, end);
return Json(list);
}
private List SearchForEvents(DateTime start, DateTime end) {
// code to get data here
}
Now, we need to modify the jQuery to call the action in our controller to return data:
$(document).ready(function() {
$('#calendar').fullCalendar({
events: '<%= Url.Action("CalendarData", "MyController") %>'
});
}
Voila!
By
Johannes Setiabudi
@
10:00 PM
0
comments! add yours!
Sunday, July 12, 2009
Adding SyntaxtHighlighter javascript with Blogger
Ever heard of "Syntax Highlighter"? This is the javascript framework that converts all the plain text code in my blog (and many other blogs, like Scott Hanselman's) into a neat and highlighted code segments with line number etc - almost like looking at it in an IDE.
You can review, download, and get the main instructions here.
This post is about how to use it with Blogger, Google's blogging engine. Which includes steps in modifying the blogger template of your choosing.
<link href='http://alexgorbatchev.com/pub/sh/current/styles/shCore.css' rel='stylesheet' type='text/css'/>
<link href='http://alexgorbatchev.com/pub/sh/current/styles/shThemeDefault.css' rel='stylesheet' type='text/css'/>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shCore.js' type='text/javascript'/>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushCpp.js' type='text/javascript'/>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushCSharp.js' type='text/javascript'/>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushCss.js' type='text/javascript'/>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushJava.js' type='text/javascript'/>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushJScript.js' type='text/javascript'/>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushSql.js' type='text/javascript'/>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushXml.js' type='text/javascript'/>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shLegacy.js' type='text/javascript'/>
<script language='javascript'>
SyntaxHighlighter.config.bloggerMode = true;
SyntaxHighlighter.all();
dp.SyntaxHighlighter.HighlightAll('code');
</script>
So now, how do you use it? It's pretty easy. Read here for for the usage/user's guide. In essence, you will just need to surround your "code" with a "pre" tag and depending on what coding language your code is, you will need to assign certain values to the "pre" tag's attribute. Here are some examples:
// for HTML/XML
<pre class="brush:html">
<UL id=sortable>
<li>one</li>
<li>two</li>
<li>three</li>
<li>four</li>
</ul>
</pre>
// for javascript
<pre class="brush:js">
alert("Hello world");
</pre>
// for C#
<pre class="brush:c#">void dfShipper_DeletingItem(object sender, System.ComponentModel.CancelEventArgs e)
{
northwindDSContext.DeleteObject(dfShipper.CurrentItem);
northwindDSContext.BeginSaveChanges((asyncResult) =>
{ northwindDSContext.EndSaveChanges(asyncResult); }, null);
}
</pre>
-- read more and comment ...
By
Johannes Setiabudi
@
10:25 PM
0
comments! add yours!
Monday, June 8, 2009
jQuery UI Sortable with TABLE
Drag and drop sorting on a web application? This thought is so far fetched several years ago - and now everybody is or can do that easily with jQuery. Looking at the tutorials and documentation in jQuery's website, it lays out a simple method to call to make our list to become sortable.
$(function() {
$("#sortable").sortable();
$("#sortable").disableSelection();
});
With our corresponding HTML:
<ul id=sortable>
<li>one</li>
<li>two</li>
<li>three</li>
<li>four</li>
</ul>
Here is a demo on how that works.
<table id=anothersortable>
<tbody class=content>
<tr><td>one</td></tr>
<tr><td>two</td></tr>
<tr><td>three</td></tr>
<tr><td>four</td></tr>
</tbody>
</table>
Then our jQuery to be as such:
$(function() {
$("#anothersortable tbody.content").sortable();
$("#anothersortable tbody.content").disableSelection();
});
Click for demo for the simple table.You can even make this having sub-sort - or with children sorting. Like this:
<table id=subsortsortable>
<tbody class=content>
<tr><td>one</td></tr>
<tr><td>two</td></tr>
<tr><td>
<table><tbody class=subcontent>
<tr><td>three.one</td></tr>
<tr><td>three.two</td></tr>
</tbody></table>
</td></tr>
<tr><td>four</td></tr>
</tbody>
</table>
Adjust our jQuery to be as such:
$(function() {
$("#subsortsortable tbody.content").sortable();
$("#subsortsortable tbody.content").disableSelection();
$("tbody.subcontent").sortable();
$("tbody.subcontent").disableSelection();
});
Click for demo of this one.
UPDATE:
Viewer Coolboy in his comment below pointed out that viewing in IE7 may sometimes introduce unexpected behavior in the y axis. I can replicate the problem and have found a solution or a work around for it by using "handler".
Using handler, you basically designating a "dragging" point, instead of using the whole row as to drag. So in using handler, our code changes a little bit in both HTML and javascript.
Here is the updated HTML:
<table id=subsortsortable>
<tbody class=content>
<tr><td><label class="levelonehandle">X</label></td><td>one</td></tr>
<tr><td><label class="levelonehandle">X</label></td><td>two</td></tr>
<tr><td><label class="levelonehandle">X</label></td><td>
<table><tbody class=subcontent>
<tr><td><label class="leveltwohandle">X</label></td><td>three.one</td></tr>
<tr><td><label class="leveltwohandle">X</label></td><td>three.two</td></tr>
</tbody></table>
</td></tr>
<tr><td><label class="levelonehandle">X</label></td><td>four</td></tr> </tbody>
</table>
Then our javascript as such:
$(function() {
$("#subsortsortable tbody.content").sortable({
handle: ".levelonehandle"
});
$("#subsortsortable tbody.content").disableSelection();
$("tbody.subcontent").sortable({
handle: ".leveltwohandle"
});
$("tbody.subcontent").disableSelection();
});
By
Johannes Setiabudi
@
9:49 PM
32
comments! add yours!
Thursday, May 28, 2009
Cascading Drop Down with ASP.NET MVC, jQuery with JSON
Cascading drop down is webform is pretty easy by using postback - or UpdatePanel. In MVC, how would it be done? jQuery comes to the rescue for this problem. Since ASP.NET MVC is able to return a JSON format result, what we need to do then is just calling that Controller's Action via jQuery and then display the drop down. Let's use an example:Say I want to list available counties per state. So the the first drop down will be the state drop down, and based on the selection of the state, the second drop down will display available counties for the selected state.
<%= Html.DropDownList("StateID", Model.StateList) %>
<select name="CountyID" id="CountyID"></select>
So since we need to (re)populate the county drop down for each selection/change of the StateID drop down, we use the .change method in jQuery.
$(document).ready(function() {
$("#StateID").change(function() { });
});
First, we need to get the selected State and also make sure that the default State selection will also execute and display the list of Counties appropriately.
$(document).ready(function() {
$("#StateID").change(function() {
var strStateID = "";
strStateID = $(this)[0].value; // get the selected state id
})
.change(); // making sure the event runs on initialization for default value
});
Once we have the state id, we can then call our controller's action to get a list of counties back via AJAX.
$(document).ready(function() {
$("#StateID").change(function() {
var strStateID = "";
strStateID = $(this)[0].value; // get the selected state id
var url = "/MyController/Counties/" + strStateID;
// call controller's action
$.getJSON(url, null, function(data) {
// do something once the data is retrieved
});
})
.change(); // making sure the event runs on initialization for default value
});
With the data in hand, we can (re)build the County drop down with the values returned from the controller.
$(document).ready(function() {
$("#StateID").change(function() {
var strStateID = "";
strStateID = $(this)[0].value; // get the selected state id
var url = "/MyController/Counties/" + strStateID;
// call controller's action
$.getJSON(url, null, function(data) {
// do something once the data is retrieved
$("#CountyID").empty();
$.each(data, function(index, optionData) {
$("#CountyID").append("<option value='"
+ optionData.CountyID
+ "'>" + optionData.CountyName
+ "</option>");
});
});
})
.change(); // making sure the event runs on initialization for default value});
By
Johannes Setiabudi
@
10:14 PM
10
comments! add yours!
Wednesday, March 18, 2009
ASP.NET Lightweight Automation Framework - Add, Edit, Delete (3/3)
In the last post, we discussed about LAF & how to test a page with list on it. We did paging, sort, and simple display. Now in this post I will show you how to do a test for Add/Edit and Delete.
Here is the code for testing Add Customer functionality from the UI. The essence of the code is that after navigating to the Customer List page, we click on the "New Customer" link with an expectation that the new customer form will show (so we verify it). Then after the form shows, fill it in with information and click "Save" button. This then should close the form and redisplay the list with the new Customer in it - so we verify that it is in there. At this point, our Add is already working. I included at the same time, a test for common edit & deletion.
[WebTestMethod]
public void AddCustomer()
{
HtmlPage page = new HtmlPage("");
// navigate to Customer
page.Navigate("/Customer/");
// Verify search result
HtmlTableElement gridView = (HtmlTableElement)page.Elements.Find("CustomerListingTable");
Assert.IsNotNull(gridView);
// click new Customer
page.Elements.Find("a", "New Customer", 0).Click(WaitFor.None);
System.Threading.Thread.Sleep(1000);
// verify new form exists
Assert.IsTrue(page.Elements.Find("CustomerDetail").IsVisible());
Assert.IsTrue(page.Elements.Exists("Cancel"));
// enter information
page.Elements.Find("FirstName").SetText("AFIRST");
page.Elements.Find("LastName").SetText("ALAST");
page.Elements.Find("MiddleInitial").SetText("A");
page.Elements.Find("DoB").SetText("1/1/1999");
page.Elements.Find("TitleId").SetSelectedIndex(0);
// click submit
page.Elements.Find("Save").Click(WaitFor.None);
System.Threading.Thread.Sleep(1000);
// verify entry in list
Assert.IsFalse(page.Elements.Find("CustomerDetail").IsVisible());
Assert.IsTrue(gridView.Rows[1].Cells[(int)ColumnNames.LastName].GetInnerText() == "ALAST");
// click detail
gridView.Rows[1].Cells[0].ChildElements[0].Click(WaitFor.None);
System.Threading.Thread.Sleep(1000);
// click edit
page.Elements.Find("a", "Edit", 0).Click(WaitFor.None);
System.Threading.Thread.Sleep(1000);
// edit information
page.Elements.Find("FirstName").SetText("AFIRSTUPDATED");
page.Elements.Find("LastName").SetText("ALASTUPDATED");
page.Elements.Find("MiddleInitial").SetText("B");
page.Elements.Find("DoB").SetText("2/2/2000");
page.Elements.Find("TitleId").SetSelectedIndex(1);
// click submit
page.Elements.Find("Update").Click(WaitFor.None);
System.Threading.Thread.Sleep(1000);
// verify entry in list
Assert.IsFalse(page.Elements.Find("IdentityDetail").IsVisible());
Assert.IsTrue(gridView.Rows[1].Cells[(int)ColumnNames.LastName].GetInnerText() == "AFIRSTUPDATED");
// click detail
gridView.Rows[1].Cells[0].ChildElements[0].Click(WaitFor.None);
System.Threading.Thread.Sleep(1000);
// click delete with confirm
page.Elements.Find("a", "Delete", 0).Click(new CommandParameters(WaitFor.None, PopupAction.ConfirmOK));
System.Threading.Thread.Sleep(1000);
// verify
Assert.IsTrue(gridView.Rows[1].Cells[(int)ColumnNames.LastName].GetInnerText() != "ALAST");
}
This is a very rudimentary test only testing best case scenarios where add, edit, and delete are successful. In my project, I also build tests for if there are any error during saving, or business rules violations, when somebody hit cancel, etc. But, the simple example above should provide enough basis to be built on top of for those other tests.
- Part 2: List, Paging, Sorting
- Part 3: Add, Edit, Delete
-- read more and comment ...
By
Johannes Setiabudi
@
7:09 AM
0
comments! add yours!
Tuesday, December 16, 2008
CSLA & ASP.NET MVC (part 3: Adding)
As I have mentioned previously in the last post, editing and adding is not that much different - one pulls an existing one and modify it with incoming data, the other is just creating a new instance and filling it up with incoming data. We discussed "editing" in my last post, and now we are going elaborate on "adding".
First, let's take a look on the displaying of the empty form. This one is pretty easy, just get a new customer and bind it into the model as CurrentCustomer.
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult New()
{
viewData.CurrentCustomer = Customer.NewCustomer();
viewData.CustomerList = CustomerInfoList.GetCustomerInfoList();
viewData.Titles = TitleInfoList.GetTitleInfoList();
return View("New", viewData);
}
We also want to bind the list of titles to be able to populate the drop down for title selection.
in handling the post, we are doing essentially the same thing as in edit, except this time we are mapping it to en empty object since it is a new one. [ActionName("New"), AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create()
{
try
{
Customer customer = Customer.NewCustomer();
UpdateModel(customer, new[]
{
"TitleId",
"FirstName",
"MiddleName",
"LastName",
"DOB"
});
customer.DateEntered = DateTime.Now;
customer.DateUpdated = DateTime.Now;
if (!customer.IsValid)
{
foreach (Csla.Validation.BrokenRule brokenRule in customer.BrokenRulesCollection)
{
ModelState.SetAttemptedValue(brokenRule.Property, brokenRule.Property);
ModelState.AddModelError(brokenRule.Property, brokenRule.Description);
}
viewData.Titles = TitleInfoList.GetTitleInfoList();
viewData.CurrentCustomer = customer;
return View(viewData);
}
else {
customer.Save();
TempData["Message"] = "I saved " + customer.LastName + " to the database";
return RedirectToAction("List", "Customer");
}
catch (Exception ex)
{
TempData["ErrorMessage"] = ex.Message;
return RedirectToAction("New");
}
}
So upon save, we want to display the confirmation message whether there is an error or the record is saved successfully. In the code above we also utilize CSLA rules validation - this is really useful in a way that we have a central place to put our format rules, business rules, validation at. If there is an error, we want to redisplay the new customer screen and if save is successful, we want to update the list with the current data.
Related Posts:
ASP.NET MVC, AJAX, jQuery
CSLA & ASP.NET MVC (part 1)
CSLA & ASP.NET MVC (part 2)
-- read more and comment ...
By
Johannes Setiabudi
@
4:36 PM
0
comments! add yours!
Saturday, December 13, 2008
CSLA & ASP.NET MVC (part 2: Editing)
In the last post, we discussed about listing viewing detail for objects built with CSLA framework via ASP.NET MVC. Now in this post, I will show the editing and adding of the object - in our example here, using "Customer".
In essence, editing and adding is not that much different - one pulls an existing one and modify it with incoming data, the other is just creating a new instance and filling it up with incoming data. In our code, we try to leverage CSLA as much as possible, where the "Save" method is called only when the object is "dirty". Another thing is that we also want to get as much as data validation within the CSLA object as possible rather than manual/custom checking in our controller.
First, editing. [AcceptVerbs(HttpVerbs.Get)]
public ActionResult Edit(int id)
{
viewData.CurrentCustomer = Customer.GetCustomer(id);
viewData.Titles = TitleInfoList.GetTitleInfoList();
return View("~/Views/Customer/Controls/CustomerEdit.ascx", viewData);
}
The method Edit is tagged with "AcceptVerbs" attribute and scoped to only accept "Get" request. What this means is that this method can and will only be executed during a GET. Scott Guthrie has an excellent post regarding this attributes in his blog - I suggest for you to check it out.
The rest of the code is pretty simple, get the Customer record that is selected (passed in as a Id parameter in the method), put the customer instance into my viewData, get the list of titles to populate my Titles drop down, and then pass the view data into the viewer - pretty straight forward.
Now, let's take a look at the handler code for edit submission/post - for when somebody hit submit on our edit form. [ActionName("Edit"), AcceptVerbs(HttpVerbs.Post)]
public ActionResult Update(int id)
{
try
{
Customer customer = Customer.GetCustomer(id);
UpdateModel(customer, Request.Form.AllKeys);
if (!customer.IsValid)
{
foreach (Csla.Validation.BrokenRule brokenRule in customer.BrokenRulesCollection)
{
ModelState.SetAttemptedValue(brokenRule.Property, customer.GetType().GetProperty(brokenRule.Property).GetValue(customer, null).ToString());
ModelState.AddModelError(brokenRule.Property, brokenRule.Description);
}
viewData.CustomerList = CustomerInfoList.GetCustomerInfoList();
viewData.Titles = TitleInfoList.GetTitleInfoList();
viewData.CurrentCustomer = customer;
viewData.ValidationErrorFlag = true;
return View("~/Views/Customer/Controls/CustomerEdit.ascx",viewData);
}
else
{
if (customer.IsDirty)
{
customer.DateUpdated = DateTime.Now;
customer.Save();
TempData["Message"] = "I saved " + customer.LastName + " to the database";
}
else
{
TempData["Message"] = "There were no changes to be made";
}
return null;
}
}
catch (Exception ex)
{
TempData["ErrorMessage"] = ex.Message;
return RedirectToAction("Edit", new { id = id });
}
}
OK, that seems long - so let's examine the code bit by bit so we can fully understand what is going on. If you notice, above the method name, there is also an "AcceptVerb" attribute, but this time it is set to "POST". Another thing is that it has ActionName("Edit") - which when combined with the AcceptVerb attribute, it will have the meaning that if there is an action "Edit" called on the controller with a POST, it will then get redirected into this method "Update".
try
{
Customer customer = Customer.GetCustomer(id);
UpdateModel(customer, Request.Form.AllKeys);
...
The 2 lines of code above, it is basically getting the Customer record being edited, and then call "UpdateModel" method, where it tries to match the instance of Customer called "customer" with the data submitted into the Request.Form. if (!customer.IsValid)
{
foreach (Csla.Validation.BrokenRule brokenRule in customer.BrokenRulesCollection)
{
ModelState.SetAttemptedValue(brokenRule.Property, customer.GetType().GetProperty(brokenRule.Property).GetValue(customer, null).ToString());
ModelState.AddModelError(brokenRule.Property, brokenRule.Description);
}
viewData.Titles = TitleInfoList.GetTitleInfoList();
viewData.CurrentCustomer = customer;
viewData.ValidationErrorFlag = true;
return View("~/Views/Customer/Controls/CustomerEdit.ascx",viewData);
}
...
Here we check whether the instance filled with data from the form is valid based on the rules specified in the CSLA rules. If it is not valid then iterate the broken rules collection and set the model marked with error messages appropriately. Now after the model is marked with the error, we want to display back the form with the model so the error messages can be displayed accordingly field by field. To do this, we then populate the Titles field in our viewdata back with list of available titles, and also populating our CurrentCustomer property with the edited customer, set the error flag and return the viewer for "Edit". else
{
if (customer.IsDirty)
{
customer.DateUpdated = DateTime.Now;
customer.Save();
TempData["Message"] = "I saved " + customer.LastName + " to the database";
}
else
{
TempData["Message"] = "There were no changes to be made";
}
return null;
}
...
If the instance does not violate any rules, then we can save if necessary. Even though CSLA will detect automatically whether the instance is dirty or not before saving to the database, but we chose to check in our controller so we then can display whether there are data being saved or not. Since there is nothing else needed to be done after the saving, we then return null value.
Related Posts:
ASP.NET MVC, AJAX, jQuery
CSLA & ASP.NET MVC (part 1)
CSLA & ASP.NET MVC (part 3)
-- read more and comment ...
By
Johannes Setiabudi
@
10:22 PM
0
comments! add yours!
Wednesday, December 10, 2008
CSLA & ASP.NET MVC (part 1: listing & viewing detail)
The easiest implementation for ASP.NET MVC is usually via LINQ to SQL. Now, for larger projects that must be scalable, one will need object development framework that is also scalable and more robust. My framework of choice CSLA.NET. Assuming you have built your CSLA classes, wiring it in with MVC is a piece of cake.
I recommend to make your view to be strongly typed to the object of your controller. So in my example, I have a CSLA class for "Customer" and also its corresponding read-only list, read-only item, editable, etc. Hence, I name my controller to be "CustomerController". In it, I created a class to carry around stuff as a single object, instead of stuffing everything in ViewData and cast when needed. public class CustomerControllerViewData
{
// list of read-only customer available to me
public CustomerInfoList CustomerList { get; set; }
// current editable customer seleted
public Customer CurrentCustomer { get; set; }
// list read-only Title available to the Customer
public TitleInfoList Titles { get; set;}
}
Then in the controller class, I declared a global variable to hold the instance of the CustomerControllerViewData class. I initialized it right away. public class CustomerController : Controller
{
CustomerControllerViewData viewData = new CustomerControllerViewData();
public ActionResult Index()
{
return RedirectToAction("FullList");
}
...
}
During list, I put all the necessary data into CustomerControllerViewData class, rest the validation, and then I pass that instance into the viewer as a strongly typed model. I do not fill in the CurrentCustomer property nor the Titles - since I won't be needing those to display my list of customers. public ActionResult List()
{
viewData.CustomerList = CustomerInfoList.GetCustomerInfoList();
viewData.ValidationErrorFlag = false;
return View("~/Views/Customer/Controls/CustomerListing.ascx", viewData);
}
The viewer looks like this - it should be pretty simple with the exception that it is strongly typed. So in the code behind, I have to add the type in the generic constructor of the viewer: public partial class CustomerListing : System.Web.Mvc.ViewUserControl
{
...
}
Now for viewing detail if a customer, we also do not need to fill out CustomerList property, since at this point we only care about a specific customer. Titles is needed since to populate a look up/drop down field. public ActionResult Detail(int id)
{
viewData.CurrentCustomer = Customer.GetCustomer(id);
viewData.Titles = TitleInfoList.GetTitleInfoList();
viewData.ValidationErrorFlag = false;
return View("~/Views/Customer/Controls/CustomerDetail.ascx", viewData);
}
Do the same thing for the code behind of the viewer to make it strongly typed: public partial class CustomerDetail : System.Web.Mvc.ViewUserControl
{
...
}
Related Posts:
ASP.NET MVC, AJAX, jQuery
CSLA & ASP.NET MVC (part 2)
CSLA & ASP.NET MVC (part 3)
-- read more and comment ...
By
Johannes Setiabudi
@
10:18 PM
4
comments! add yours!
Thursday, November 6, 2008
Using PageMethods & JSON to provide auto population
One of the problem that I have to solve in my recent project was to provide a look up for city, county, state based on a zip code. There are multiple ways of doing this - but in this exercise, I want to demonstrate using javascript (client-side) to call PageMethods (server-side) and then populate my fields.
1. Set EnablePageMethod to true in your script manager
2. Create your PageMethod
When the PageMethod returns its value, it will get serialized into JSON object. In my example above, I an returning a IEnumerable
3. Create your javascript to call the PageMethod and callback handler
When you call a PageMethod, the result from the PageMethod is directly transfered into your callback function. In my example below - it is transfered into "result". You can also specify success path callback and failure path callback if you want.function GetZip(zipBox) {
var zip = zipBox.value;
if (zip.toString().length >= 5) {
var x = PageMethods.GetCityCountyState(zip, GetCityCountyState_Callback);
}
function GetCityCountyState_Callback(result) {
cityDDL = document.getElementById("cityDDL");
cityDDL.options.length = 0;
var oldValue = "";
for (i = 0; i < result.length; i++) {
if (oldValue != result[i][1]) {
var newValue = result[i][1];
var newText = result[i][2];
var objOption = new Option(newText, newValue);
cityDDL.options.add(objOption);
oldValue = newValue;
}
}
countyDDL = document.getElementById("countyDDL");
countyDDL.options.length = 0;
oldValue = "";
for (i = 0; i < result.length; i++) {
if (oldValue != result[i][3]) {
var newValue = result[i][3];
var newText = result[i][4];
var objOption = new Option(newText, newValue);
countyDDL.options.add(objOption);
oldValue = newValue;
}
}
stateDDL = document.getElementById("stateDDL");
stateDDL.options.length = 0;
oldValue = "";
for (i = 0; i < result.length; i++) {
if (oldValue != result[i][5]) {
var newValue = result[i][5];
var newText = result[i][6];
var objOption = new Option(newText, newValue);
stateDDL.options.add(objOption);
oldValue = newValue;
}
}
}
So in my javascript above, I basically waiting until the textbox for zipcode is filled with 5 numbers before calling the PageMethod. Once I get the result back as JSON object, my callback function will take over and populate my drop down list for City, County, and State.
Additional readings:
1. ASP.net: Exposing WebServices To AJAX Tutorial
2. AJAX PageMethods, JSON Serialization, and a little bit of LINQ databinding
3. Passing JSON param
Related Posts:
ASP.NET MVC, AJAX, jQuery
By
Johannes Setiabudi
@
1:21 PM
1 comments! add yours!
Thursday, July 31, 2008
ASP.NET MVC, AJAX, and JQuery
I have been developing asp.net application from .NET framework 1.0, 1.1, 2.0, 3.0 - so pretty much from the begining. Nowadays, what really excites me (as far as programming goes) is ASP.NET MVC. The MVC model has been out there for a while in the Java world or Ruby world (with rails). But it is only since .NET Framework 3.5 that Microsoft ASP.NET starts to pick it up. How about that, huh? The ability to do that in 1 line of code!
One thing that I really like about MVC (compared to ASP.NET webform) is the ability to control your HTML directly. This therefore empowers you to create your own Javascript component easier. In a way, it is a bit more manual then webform, but the total control and flexibility really pays off.
AJAX therefore then can become TRUE AJAX, rather than "fake" AJAX like webform's UpdatePanel. Payload is much smaller between client and server - which makes MVC app super fast (if done right, especially with AJAX).
ASP.NET MVC also enables you to have a TDD (test driven development) approach to UI development. Since all "controls" or "pages" are rendered by invoking an "Action" methods - which is just a regular method - there those methods can be called by a Unit Test of your choice and checked.
.NET framework 3.5 allows you to have pretty URL too. Initially baked into MVC assemblies, but in SP1 it will be released as part of the framework itself.
So, how do you code MVC? Is it really any different than C# or VB? Well, here is the thing, MVC is not a language or third party tools. It is more of a UI development framework. So you still use the same language (like C#, VB, etc).
For me, development in MVC pattern have been quite an experience. It really brought back the true power of separation between your model to your view/presenter but in a very powerful manner. Having a strong tight and concise HTML combined with the ability to maximize your Javascript without the use of 3rd party controls really opens tons of possibilities - this is really where you can fully utilize AJAX, in which I choose to use JQuery.
JQuery is a javascript framework. It is really powerful because it has a superb selectors - therefore with concise code, you can really do a lot of stuff that normally will take tons of code. So, what does it look like?
$("#surprise").slideToggle();
In JQuery website, you can read about all the APIs and its capabilities. It is quite amazing and opens new possibilities for your UI development.
You can read more about ASP.NET MVC:
Code Plex
An Architectural View of the ASP.NET MVC Framework
ASP.NET page
Scott Gu's Blog
JQuery:
JQuery
-- read more and comment ...
By
Johannes Setiabudi
@
3:41 PM
0
comments! add yours!