dileno

Subscribe

Hi! I'm Martin Söderlund, the owner of this blog. I work as a web consultant in Stockholm, Sweden. My main focus areas are .NET development and interface development.
If you've got something on your mind, feel free to contact me.

Close

Thank you for visiting!

Please consider subscribing to the RSS feed or following me on Twitter.

Real Error Messages from IIS

If you want real error messages for your web application in the development environment, make sure you do this:

In IIS:

  1. Go to your web application under Sites and choose .NET Error Pages in the right pane.
  2. Click Edit Feature Settings in the most right pane.
  3. Make sure Mode is set to Off:
    IIS: Error Pages Off

In Web.Config:

Make sure the following httpErrors element is in the <system.webServer> node for the application, with errorMode set to Detailed and existingResponse set to PassThrough:

<httpErrors errorMode="Detailed" existingResponse="PassThrough">
    <remove statusCode="404" subStatusCode="-1" />
    <error statusCode="404" path="/404" responseMode="ExecuteURL" />
</httpErrors>

The 404 handling in above code is just for good measure.

Now you should once again get real .NET error messages from IIS.

Angular Delay with Debounce

Recently we were trying out a few things to delay validation of form fields in our Angular application. The not so good solution, was this:

<input type="text" ng-keyup="validate()" />

As soon as a keyboard key was released, the validate method was triggered. A little bit too often.

So we wanted something that created a delay in our validation. You could add a timeout handler in the validate function, but it wouldn't help, as the validate method would be called numerous times anyway, but with a delay.

In steps ng-change and ng-model-options with debounce. This is Angular 1.5.8. The new code that works really well:

<input type="text" ng-change="validate()" ng-model-options='{ debounce: 1000 }' />

This creates a delay of 1000 ms before the validate method is triggered.

Angular 2 version

Use RxJs Observables and the debounceTime() operator. Here's a good Stack Overflow thread on Angular 2 and debounceTime. In short, the pseudo code looks like this:

this.term.valueChanges
             .debounceTime(400)
             .subscribe(term => this.wikipediaService.search(term).then(items => this.items = items));

Further reading here.

Ajax File Download That Works!

So you want to download a file and show an Ajax loader until the download is complete? Here's a way to do it:

  1. User clicks the download button and a JavaScript function is called.  In this JS function, a number of things will happen:
    • Show an AJAX loader.
    • Create a cookie.
    • Run a check cookie function.
    • Redirect to the file download (in this case an MVC method that returns the file).
  2. If successful, the MVC method removes the cookie and returns the file. When the cookie is removed, disable the Ajax loader (happens in check cookie function).
  3. Done.

Step 1 - JS call

User clicks our download button and we call this export function. Note: just before we create the timer and cookieName variables.

var timer = null;
var cookieName = 'App_FileExportCookie';
	
var export = function () {
    $('#ajax-loader').show();

    var cookie = $.cookie(cookieName);

    if (cookie === undefined) {
        cookie = $.cookie(cookieName, 0);
    }
    checkCookie();

    window.location = '/FileExport';
}

We show the Ajax loader and then check if a cookie exists (using jQuery Cookie plugin). Finally we redirect to the URL where the actual file generation and download will happen.

Step 2 - Check cookie

In step 1, we called the checkCookie function. This one is really important as it will check and see the status of the file download, through checking our cookie.

var checkCookie = function (doClearTimeout) {

    if (doClearTimeout) {
        clearTimeout(timer);
    }
    else {
        timer = setTimeout(function () {

            var cookie = $.cookie(cookieName);

            if (cookie === undefined) {
                $('#ajax-loader').hide();
	        checkCookie(true);
	    } else {
            checkCookie(false);
	    }
	}, 1500);
    }
}

What will happen here, is we set a timeout where we look for our cookie. We call this function until we can't find the cookie we created in step 1 any more. When the cookie doesn't exist, we hide the AJAX loader and clear the timeout.

Finally, we need a place to remove the cookie. Enter step 3.

Step 3 - file generation and remove cookie

In step 1, we redirected the user to the /FileExport url. In ASP.NET MVC, we will have an ActionResult with that name and here we will generate and return the file, plus remove the cookie we created in the beginning. The final code:

private string _fileCookieName = "App_FileExportCookie";
private const string _excelMimeType =
 "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";

public FileResult FileExport()
{
    ExcelFile excel;
	
    try {
        excel = GenerateExcel();
    }
    catch (Exception ex)
    {
        // handle exceptions
    }
    finally
    {
	// same as in JavaScript cookie name
	var cookieName = _fileCookieName;
	var cookie = Request.Cookies[_fileCookieName];

	if (cookie != null)
	{
    	    cookie.Expires = DateTime.Now.AddDays(-1);
	    Response.SetCookie(cookie);
        }
    }
	
    return File(excel.FilePath, _excelMimeType);
}

This is just some pseudo code for generating an Excel file, the important stuff happens in the finally block. We look for our cookie and remove it once the file is generated. Finally, we return the file in proper Excel format.

That's it!

IE Edge, Angular and Highlighting a Text Field

Recently, I stumbled upon a problem using the Angular Material framework. While using the md-autocomplete component, I wanted to highlight a text field when the user clicked said text field. Easier said than done.

I started writing a directive that highlights a text field when it's focused. Of course I went for the focus event. When the focus event is triggered, it highlights the text field. It worked everywhere. Except in IE Edge.

After some debugging, I simply switched the focus event for the click event, and it started working everywhere.

Here's the directive:

app.directive('autocompleteFocus', function($timeout, $log){
  return{
    link: function(scope, element, attrs){
       $timeout(selectOnFocus, 0);

       function selectOnFocus(){
           element.find("#my-field").bind("click", function () {
               angular.element(this).select();
           });
       }
    }
 }
});

Use it like this:

<md-autocomplete ... autocomplete-focus />

To the top