Tag Archives: jQuery

Ajax file upload

Sometimes it would be useful to upload a file to a website while the rest of the page remains unchanged, so with Ajax. I’ve got bad news for you: the Level 1 version of the XMLHttpRequest object doesn’t support that, so if you must support older browsers, you need some tricks.

One of the most widely used tricks is using an iframe, however in that case the results from the server (for example the validation errors) are also delivered to the iframe. So if you work with a hidden iframe and you need the result in client-processable way in JavaScript, you have to dig it from the iframe. Fortunately the jQuery Form Plugin can help you to solve these issues.

First, create a view-model on the server, in which a HttpPostedFileBase property represents the uploaded file. I’ve also added a Name property for demonstration purposes:

public class UploadVM
{
    [Required( ErrorMessage = "Please enter a name!" )]
    public string Name { get; set; }

    [Attachment]
    public HttpPostedFileBase Attachment { get; set; }
}

The [Attachment] is the file validation attributed I presented in an earlier post. It checks whether the file is submitted, and also checks the extension and the size of the file.

For this model you can create a form that submits the file and the provided name:

@using( Html.BeginForm( "Index", "Home", FormMethod.Post, 
        new { id = "myForm", enctype = "multipart/form-data" } ) )
{
    <p>
        <label for="txtName">Name:</label>
        <input type="text" id="txtName" name="Name" />
    </p>

    <p>
        <label for="fupAttachment">File:</label>
        <input type="file" id="fupAttachment" name="Attachment" />
    </p>

    <p>
        <input type="submit" value="Upload" />
    </p>    

    <div id="errors"></div>
}

It’s important that the form must have an enctype attribute with multipart/form-data value, because that supports file upload. I also created a div with errors id, which will host the error messages.

This form posts to the Index action of the HomeController which can be implemented like this:

[HttpPost]
public ActionResult Index( UploadVM model )
{
  if( !this.ModelState.IsValid )
  {
    string firstError = ModelState.First( m => m.Value.Errors.Any() )
.Value.Errors[ 0 ].ErrorMessage;
return this.FileUploadFailure( firstError ); } // Process the file here string message = String.Format( "The file '{0}' is successfully uploaded.",
model.Name );
return this.FileUploadSuccess( message ); }

If there is any validation error in the view-model, the runtime adds them to the ModelState thanks to the attributes. Just as always the ModelState is check in the beginning of this method, and if there is any error an error message is returned, if not, then the file is processed and a success message is returned to the client.

The returned value is a JSON object, because that comes really handy on the client. But don’t forget, that it will land in an iframe, and not every browser tolerates an application/json result in iframes. Fortunately the jQuery Form Plugin supports a simple hack: just wrap the result into a <textarea> element and send it back in a text/html response, the plugin will do the rest.

To simplify (and standardize) this wrapping, you can create a custom result type:

public class FileUploadJsonResult : JsonResult
{
  public override void ExecuteResult( ControllerContext context )
  {
    this.ContentType = "text/html";
    context.HttpContext.Response.Write( "<textarea>" );
    base.ExecuteResult( context );
    context.HttpContext.Response.Write( "</textarea>" );
  }
}

You can also create extension methods for the Controller class to create these upload results just like any other result from the action methods:

public static FileUploadJsonResult FileUploadSuccess( 
this Controller controller, string successMessage = null ) { return new FileUploadJsonResult { Data = new { Success = true, Message = successMessage } }; } public static FileUploadJsonResult FileUploadFailure(
this Controller controller, string errorMessage ) { return new FileUploadJsonResult { Data = new { Success = false, Message = errorMessage } }; }

Here you can create a custom object with any structure in the Data property that will be delivered to the client in JSON. The code above just signals the result of the file upload in the Success property, and returns a detailed status message in the Message property that can be displayed by the browser.

So now you have fully functional server side: a form that POSTs to an action which validates the input, and if every field is valid, processes the values and returns a status in a JSON object.

Let’s implement the client side, of course with the jQuery Form Plugin. As its name implies, this is a jQuery plugin that you can apply to the jQuery object which wraps the form element (the $form in this case):

$form.ajaxForm({
    iframe: true,
    dataType: "json",
    beforeSubmit: function () {
// TODO
}, success: function (result) { // TODO
}, error: function () { // TODO
} });

You usually have to implement the following callback functions:

  • beforeSubmit: this is called before the POST is sent to the server. This is where you can display a “please wait” message, a progress indicator, or simply block the form controls using the jQuery BlockUI plugin.
  • success: this is called when the upload is completed successfully. At least in theory. In my experience this callback is also called when the server returns some low-level error. If there was no error, you receive the response from the server in the function parameter in JSON, but be prepared, that in case of error it can be undefined as well!
  • error: this is called when an error occurred during postback.

Here is an example of a working success callback implementation:

if (!result) {
  $errors.html('<div class="validation-summary-errors"><ul><li>Oooops....
</li></ul></div>'
); } else { $form.resetForm(); if (result.Success === true) { var message = result.Message; if (message && message.length > 0) { $errors.html( message ); } } else { $errors.html('<div class="validation-summary-errors"><ul><li>{0}
</li></ul></div>'
.format(result.Message)); } }

In this code the errors are displayed in a complex HTML fragment. The reason for that is that the same HTML fragment is generated by the standard ASP.NET MVC validation helpers, so with this code our Ajax errors will be rendered with the same style.

The format function acts like the String.Format method on the server and can be implemented like this:

String.prototype.format = function () {
  var args = arguments;
  return this.replace(/\{\{|\}\}|\{(\d+)\}/g, function (m, n) {
    if (m === "{{") { return "{"; }
    if (m === "}}") { return "}"; }
    return args[n];
  });
};

If you return all ModelState errors from the server, you can render them in a loop.

You can download the full source code with tons of comment from the following link: http://sdrv.ms/10QQLSp

 

Technorati-címkék: ,

jQuery breaks with old IE versions

jquery-logoThe latest, 1.9 version of jQuery was released today, together with the beta of the 2.0 version. Although both versions share the same API (some features were removed from 2.0 as well as from 1.9), there are huge differences between them:

  • The 1.9 version – just like the previous versions – runs on Internet Explorer 6, 7 and 8, or as they say, on “oldIE”.
  • The 2.0 version will not run on oldIE. This decision results a simpler, faster and smaller library.

According to the Release Notes, both versions will be supported in the future, but I’m afraid that support will not last for ever. Sooner or later the 1.9 version will be deprecated, and new features will be implemented only in the 2.0 version.

Who loses more on this, IE or jQuery? Developers will switch to other libraries, or websites will render IE 6-7-8 obsolete?

 

Technorati-címkék: ,,

70-481 exam preparation materials

With the release of Windows 8, the Microsoft certifications are naturally changing. The first exam of the new MCSD: Windows Metro style Apps using HTML5 certification is 70-481: Essentials of Developing Windows Metro style Apps using HTML5 and JavaScript which is currently available as a beta exam. Since I couldn’t find a complete exam preparation guide, I’ve collected some links that point to sources related to the topics of this exam.

Starters:

If you plan to take your exam in October or later, you can also pre-order the Beginning Windows 8 Application Development book.

1. Design Metro style Apps (20%)

1.1. Design the UI layout and structure.
This objective may include but is not limited to: evaluate the conceptual design; decide how the UI will be composed; design for the inheritance and re-use of visual elements (e.g., styles, resources); design for accessibility; decide when custom controls are needed

1.2. Design for separation of concerns.
This objective may include but is not limited to: plan the logical layers of your solution to meet application requirements; design loosely coupled layers; incorporate WinMD components

1.3. Design and implement Process Lifetime Management (PLM).
This objective may include but is not limited to: choose a state management strategy; handle the suspend event (oncheckpoint); prepare for app termination; handle the onactivated event; check the ActivationKind and previous state

1.4. Plan for an application deployment.
This objective may include but is not limited to: plan a deployment based on Windows 8 Application certification requirements; prepare an app manifest (capabilities and declarations); sign an app; plan the requirements for an enterprise deployment

2. Develop Metro style Apps by Using WinRT (20%)

2.1. Access and display contacts.
This objective may include but is not limited to: call the ContactsPicker (windows.applicationmodel.contacts) class; filter which contacts to display; display a set number of contacts; create and modify contact information; select specific contact data

2.2. Design for charms and contracts.
This objective may include but is not limited to: choose the appropriate charms based on app requirements; design an application to be charm- and contract-aware; configure the application manifest for correct permissions

2.3. Implement search.
This objective may include but is not limited to: provide search suggestions using the SearchPane class; search and launch other apps; provide and constrain search within an app, including inside and outside of search charm; provide search result previews; implement activation from within search

2.4. Implement Share in an app.
This objective may include but is not limited to: use the DataTransferManager class to share data with other apps; accept sharing requests by implementing activation from within Share; limit the scope of sharing using the DataPackage object; implement in-app Share outside of Share charm

2.5. Manage application settings and preferences.
This objective may include but is not limited to: choose which application features are accessed in AppSettings; add entry points for AppSettings in the Settings window; create settings flyouts using the SettingsFlyout control; add settings options to SettingsFlyout; store and retrieve settings from the roaming app data store

3. Create the User Interface (21%)

3.1. Implement WinJS controls.
This objective may include but is not limited to: flipview; flyout; grid layout; list layout; menu object

3.2. Implement HTML layout controls.
This objective may include but is not limited to: implement layout controls to structure your layout; support scrolling and zooming with CSS3; manage text flow and presentation, including overflow

3.3. Create layout-aware apps to handle view states.
This objective may include but is not limited to: handle viewState events; choose among application view states; use CSS3 media queries to handle different view states; respond to ApplicationViewStateChangedEvent

3.4. Design and implement the app bar.
This objective may include but is not limited to: determine what to put on the app bar based on app requirements; style and position app bar items; design the placement of controls on the app bar; handle AppBar events

3.5. Apply CSS styling.
This objective may include but is not limited to: implement gradients, grid layouts, zooming, scroll snapping, and media queries

4. Program User Interaction (20%)

4.1. Manage input devices.
This objective may include but is not limited to: capture gesture library events; create custom gesture recognizers; listen to mouse events or touch gestures; manage Stylus input and inking; handle drag and drop events

4.2. Design and implement navigation in an app.
This objective may include but is not limited to: handle navigation events, check navigation properties, and call navigation functions by using the WinJS.Navigation namespace; design navigation to meet app requirements; Semantic Zoom; load HTML fragments

4.3. Create and manage tiles.
This objective may include but is not limited to: create and update tiles and tile contents; create and update badges (the TileUpdateManager class); respond to notification requests; choose an appropriate tile update schedule based on app requirements

4.4. Notify users by using toast.
This objective may include but is not limited to: enable an app for toast notifications; populate toast notifications with images and text by using the ToastUpdateManager; play sounds with toast notifications; respond to toast events; control toast duration

5. Manage Security and Data (19%)

5.1. Choose a data access strategy.
This objective may include but is not limited to: choose the appropriate data access strategy (file based; web service; remote storage, including Windows Azure storage) based on requirements

5.2. Retrieve data remotely.
This objective may include but is not limited to: use XHR to retrieve web services; set appropriate HTTP verb for REST; handle progress of data requests; consume SOAP/WCF services; use WebSockets for bidirectional communication

5.3. Implement data binding.
This objective may include but is not limited to: choose and implement data-bound controls, including WinJS.UI.ListView, to meet requirements; bind data to item templates such as WinJS.Binding.Template; bind data to controls by using data-win-control and data-win-bind; configure an iterator with data-win-options; enable filtering, sorting, and grouping data in the user interface

5.4. Manage Windows Authentication and Authorization.
This objective may include but is not limited to: retrieve a user’s roles or claims; store and retrieve credentials by using the PasswordVault class; implement the CredentialPicker class

5.5. Manage Web Authentication.
This objective may include but is not limited to: use the Windows.Security.Authentication.Web namespace; set up OAuth2 for authentication; CredentialPicker; set up single sign-on (SSO); implement credential roaming; implement the WebAuthenticationBroker class

If you are aware of any other useful resource, please share its link here!

 

Technorati-címkék: ,,

OData Series Part 3: Accessing an Open Data Protocol feed from jQuery

In the third part of the series I show you how you can use jQuery and the jQuery templates plugin to connect to an OData feed directly from JavaScript.

Accessing an OData feed from jQuery

The video is hi-res, so 720p and full screen view is recommended.

You can also view the past and future episodes of the OData series.