Do not use console.log without polyfill, when you are living in 2011 (IE9) or before

If you have to support <= IE9, you should not use console.log without a polyfill. If you don’t use a polyfill, console.log will throw an error. Console.log will only be available if the developertools are open:

 

http://stackoverflow.com/questions/5472938/does-ie9-support-console-log-and-is-it-a-real-function/5473193#5473193

Chrome-and-Pointer-Events-Its-Not-Over-but-We-Need-Your-Help

Kudos to Chris Love:

 

 

 

http://www.love2dev.com/#!article/Chrome-and-Pointer-Events-Its-Not-Over-but-We-Need-Your-Help

 

 

What Can You Do?

I got wind the Blink team, that is the team that created Google’s Chrome browser, is watching the Chromium bug tracker issue #162757. This is the issue/bug report filed to have pointer events added to Chrome. They are trying to gauge how popular the API is with developers. The metric is how many times the issue is starred.

 

Chromium Pointer Events Bug Issue 162757

 

So please take a moment and tap the star in the top-left corner of the page and register your vote in support of pointer events in Chrome. Then tell some friends to do the same. Maybe the Blink team will take notice and use the code that was checked into the WebKit source almost 2 years ago and give developers an easy to use input modality abstraction API. In the end developers will have a much easier time dealing with new input modalities and end users can have better user experiences.

Fix: new XMLHttpRequest() Uncaught ReferenceError: request is not defined

I was testing some JavaScript ajax code found at: http://youmightnotneedjquery.com/ and I was getting the error:

 

Uncaught ReferenceError: request is not defined from ReferenceError: request is not defined
   at Object.rli.app.self.makeXmlHttpRequest (
http://localhost:50258/Client/Features/Posts/request_is_not_defined.html:27:25)
   at Object.rli.app.self.onExecuteClick (http://localhost:50258/Client/Features/Posts/request_is_not_defined.html:55:22)
   at HTMLButtonElement.onclick(http://localhost:50258/Client/Features/Posts/request_is_not_defined.html:12:145) request_is_not_defined.html:63
Uncaught ReferenceError: request is not defined

 

image

 

Cause

This was caused by the line:

request = new XMLHttpRequest();

When you use ‘use strict’, variables need to be defined before use.

Solution

So adding var before request fixed the problem:

<!DOCTYPE html> <html> <head> <title>Vanilla JavaScript.</title> <meta charset="utf-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1" /> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no" /> </head> <body> <div class="spa-page"> <button onclick="rli.app.onExecuteClick()">Execute</button> </div> <script type="text/javascript"> // Use a namespace to prevent pollution of the global namespace. var rli = rli || {}; // Define application root object. rli.app = (function () { 'use strict'; var self = {}; self.makeXmlHttpRequest = function () {

// When "var" is removed from this line, an error is thrown:
// Uncaught ReferenceError: request is not defined.
var request = new XMLHttpRequest();

request.open('GET', 'http://www.google.com', true); request.onload = function () { if (this.status >= 200 && this.status < 400) { // Success! var data = JSON.parse(this.response); console.log(data); } else { // We reached our target server, but it returned an error. console.log("Error status not between 200 and 400."); } }; request.onerror = function (e) { // There was a connection error of some sort. console.log(e); }; request.send(); }; self.onExecuteClick = function () { self.makeXmlHttpRequest(); }; self.start = function () { // Define global exception handler. window.onerror = function (message, file, line, col, error) { console.log(message, "from", error.stack); }; }; return self; })(); // Start the application. rli.app.start(); </script> </body> </html>

AngularJS and Breeze – A simple crud app – Part 4 – Extracting a data service and adding validation.

 

In this post all will be extracting a data service from the code created in the previous posts and I will be adding some client side validation by using the breeze directive: data-z-validate.

 

Note

All code can be found at:

https://github.com/roelvanlisdonk/Research/tree/master/Research/Research.UI.Web/Client/Features/AngularJS_and_Breeze/Part4

 

image

 

Just by adding the data-z-validate attribute to the input elements in the grid, breeze will automatically show client side validation errors, by default an asterisk “*” is shown for required fields and a message is shown, when the user clears a required field.

image

 

In this case I also added a maxlength data annotation to the lastName field:

image

 

Model

namespace Research.UI.Web.Server.Model
{
using System.ComponentModel.DataAnnotations;
public class Employee
{
[Key]
public int Id { get; set; }
[Required]
[MaxLength(20)]
public string FirstName { get; set; }
[Required]
[MaxLength(50)]
public string LastName { get; set; }
[MaxLength(20)]
public string PhoneNumber { get; set; }
}
}

Note

I encountered a problem with the data-z-validate directive, this was caused by added the directive dynamically in a custom directive created by me, see: http://stackoverflow.com/questions/22849402/angular-directive-with-a-template-does-not-work-with-z-validate but this was fixed by altering my custom directive.

 

The custom directive with fix

// Angular directive [spaField] responsible for generating grid cell controls.
spa.app.directive('spaField', ['$compile', function ($compile)
{
var directive = {
restrict: 'A', /* Restrict this directive to attributes.  */
replace: true, /* The given element will be replaced in the link function. */
link: function ($scope, element, attrs)
{
// The data-z-validate directive will append a [span class="z-decorator"] to the following [input] element, by using the jquery "append" function.
var html = '<input ng-disabled="{{vm.isKeyField(prop)}}" type="text" data-ng-model="entity[prop.name]" data-z-validate>';
if ($scope.prop.relatedNavigationProperty) {
var relatedTableName = $scope.prop.relatedNavigationProperty.nameOnServer;
html = '<select kendo-combo-box ng-model="entity[prop.name]" ng-options="record.id as record.firstName for record in vm[\'' + relatedTableName + '\']"></select>';
} else if ($scope.prop.dataType.name === "DateTime") {
html = '<input kendo-date-picker k-ng-model="entity[prop.name]" k-format="\'dd-MMM-yyyy\'" />';
} else if ($scope.prop.dataType.name === "Boolean")
{
html = '<input kendo-mobile-switch k-on-label="\'YES\'" k-off-label="\'NO\'" />';
}
// Apply scope to the created html fragment.
var compiled = $compile(html)($scope);
// Get the [<span class="z-decorator"] appended to the input element by the z-validate directive.
var span = compiled[0].parentNode.children[1];
// The following 2 lines will only add the input element to the DOM and not the [span class="z-decorator"], that is added by the z-validate directive.
element.replaceWith(compiled);
element = compiled;
// Add the [span class="z-decorator"] to the current parent element of the input element.
element.parent().append(span);
element.parent().append(span);
}
};
return directive;
}]);

AngularJS and Breeze – A simple crud app – Part 3 –Adding foreign keys and Kendo UI widgets.

 

Using Kendo UI mobile switch in AngularJS generated grid.

image

 

Using Kendo UI date picker in AngularJS generated grid.

image

 

Using Kendo UI combobox in AngularJS generated grid.

image

 

All code can be found at:

https://github.com/roelvanlisdonk/Research/tree/master/Research/Research.UI.Web/Client/Features/AngularJS_and_Breeze/Part3

 

Some highlights:

 

AngularJS directive

This directive will render the controls in the grid

spa.app.directive('ngField',['$compile', function ($compile) {
var directive = {
restrict: 'A', /* restrict this directive to elements */
link: function ($scope, element, attrs) {
var html = '<input ng-disabled="{{vm.isKeyField(prop)}}" type="text" ng-model="entity[prop.name]">';
if ($scope.prop.relatedNavigationProperty) {
var relatedTableName = $scope.prop.relatedNavigationProperty.nameOnServer;
html = '<select kendo-combo-box ng-model="entity[prop.name]" ng-options="record.id as record.firstName for record in vm[\'' + relatedTableName + '\']"></select>';
} else if ($scope.prop.dataType.name === "DateTime") {
html = '<input kendo-date-picker k-ng-model="entity[prop.name]" k-format="\'dd-MMM-yyyy\'" />';
} else if ($scope.prop.dataType.name === "Boolean")
{
html = '<input kendo-mobile-switch k-on-label="\'YES\'" k-off-label="\'NO\'" />';
}
var compiled = $compile(html)($scope);
element.replaceWith(compiled);
element = compiled;
}
};
return directive;
}]);

 

HTML

The HTML shows a splash page with the text “Loading data…” by using the ng-cloak AngularJS directive.

By putting all external resources, like “link” and “script” tags at the bottom of the page and inlining the minimal CSS to show the splash page, the splash page is immediately shown to the user, while the AngularJS app is booted and the data is loaded.

<!DOCTYPE html>
<html data-ng-app="app">
<head>
<title data-ng-bind="title">Angular and Breeze</title>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no" />
<!-- All external resources are moved to the bottom of the page, to allow direct rendering of the [splash screen]. -->
<!-- Only the styling for the [loader / splash screen] is included in the head. -->
<style type=text/css>
html, body {
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box; /* Border boxing is used, so the padding, margin and borders are within the width and height of the element. */
height: 100%;           /* Full screen single page app. */
margin: 0;              /* Prevent unnecessary white space. */
max-height: 100%;       /* Full screen single page app. */
outline: 0;             /* Prevent unnecessary white space. */
padding: 0;             /* Prevent unnecessary white space. */
}
body {
padding: 20px;
}
div.spa-splash {
display: none;
}
div.spa-splash, div.spa-splash > div {
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box; /* Border boxing is used, so the padding, margin and borders are within the width and height of the element. */
height: 100%;           /* Full screen single page app. */
max-height: 100%;       /* Full screen single page app. */
padding: 20px;            
}
div.spa-splash > div {
border: 1px solid rgb(212, 212, 212);
padding: 10px;
}
[ng-cloak].spa-splash {
display: block !important;
}
[ng-cloak] {
display: none;
}
</style>
</head>
<body>
<div class="spa-splash" ng-cloak><div>Loading data...</div></div>
<div class="spa-page container" data-ng-controller="admin as vm" ng-cloak>
<div class="spa-page-sidebar">
<div>Tables</div>
<div ng-repeat="entityType in vm.entityTypes"><a class="spa-action-link" ng-click="vm.refresh(entityType)">{{ entityType.shortName }}</a></div>
</div>
<div class="spa-page-content">
<div class="spa-grid-toolbar">
<a class="spa-action-link" ng-click="vm.save()">save</a> |
<a class="spa-action-link" ng-click="vm.reset()">reset</a> |
<a class="spa-action-link" ng-click="vm.create()">create</a>
<i class="fa fa-exclamation-circle"
title="Some data has change. Press save to save the changes to the server!"
ng-show="vm.isDirty"></i>
</div>
<table class="spa-grid">
<thead>
<tr>
<th> </th>
<th ng-repeat='(key, prop) in vm.entityDataFields'>{{ prop.name }}</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="entity in vm.entities">
<td><a class="spa-action-link" ng-click="vm.delete(entity)">delete</a></td>
<td ng-repeat='(key, prop) in vm.entityDataFields'>
<div ng-field></div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<!-- Libraries -->
<link rel="stylesheet" type="text/css" href="../../../Libraries/FontAwesome/css/font-awesome.min.css" />
<link rel="stylesheet" type="text/css" href="../../../Libraries/Toastr/toastr.min.css" />
<!-- App -->
<link rel="stylesheet" type="text/css" href="app.css" />
<!-- Libraries -->
<script type="text/javascript" src="../../../Libraries/jQuery/jquery-2.1.1.js"></script>
<script type="text/javascript" src="../../../Libraries/Angular/angular.js"></script>
<!-- Kendo -->
<link rel="stylesheet" type="text/css" href="//cdn.kendostatic.com/2014.2.625/styles/kendo.common.min.css" />
<link rel="stylesheet" type="text/css" href="//cdn.kendostatic.com/2014.2.625/styles/kendo.rtl.min.css" />
<link rel="stylesheet" type="text/css" href="//cdn.kendostatic.com/2014.2.625/styles/kendo.metro.min.css" />
<link rel="stylesheet" type="text/css" href="//cdn.kendostatic.com/2014.2.625/styles/kendo.metro.mobile.min.css" />
<script type="text/javascript" src="//cdn.kendostatic.com/2014.2.625/js/kendo.all.min.js"></script>
<!-- Breeze -->
<script type="text/javascript" src="../../../Libraries/Breeze/breeze.debug.js"></script>
<script type="text/javascript" src="../../../Libraries/Breeze/breeze.angular.js"></script>
<!-- Add toastr which needs jQuery (Breeze does not need jQuery). -->
<script type="text/javascript" src="../../../Libraries/Toastr/toastr.js"></script>
<script type="text/javascript" src="../../../Libraries/Moment/moment.js"></script>
<script type="text/javascript" src="../../../Libraries/Spin/spin.js"></script>
<!-- Add breeze.savequeuing which needs Q (Breeze does not need Q). -->
<script type="text/javascript" src="../../../Libraries/Q/q.min.js"></script>
<script type="text/javascript" src="../../../Libraries/Breeze/breeze.savequeuing.js"></script>
<!-- App -->
<script type="text/javascript" src="app.js"></script>
</body>
</html>

Controlling position of a custom confirm dialog with Kendo UI

The native confirm dialog, shown when you use the confirm function in JavaScript can’t be positioned in JavaScript.

A Kendo UI window can be positioned.

 

 

image

 

HTML

<!DOCTYPE html>
<html>
<head>
<title>Kendo element binding research page.</title>
<link rel="stylesheet" type="text/css" href="//cdn.kendostatic.com/2014.1.528/styles/kendo.common.min.css" />
<link rel="stylesheet" type="text/css" href="//cdn.kendostatic.com/2014.1.528/styles/kendo.rtl.min.css" />
<link rel="stylesheet" type="text/css" href="//cdn.kendostatic.com/2014.1.528/styles/kendo.metro.min.css" />
<link rel="stylesheet" type="text/css" href="//cdn.kendostatic.com/2014.1.528/styles/kendo.metro.mobile.min.css" />
<link rel="stylesheet" type="text/css" href="//netdna.bootstrapcdn.com/font-awesome/4.1.0/css/font-awesome.min.css">
<style>
/* Resets */
div, span, i, p, input, select {
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box; /* Border boxing is used, so the padding, margin and borders are within the width and height of de element. */
color: rgba(112, 112, 112, 1);
font-family: Arial, Helvetica, sans-serif; /* For know use default fonts used on google.com stackoverflow.com, telerik.com etc. */
font-size: 13px;
margin: 0; /* Margin zero is used to prevent unnecessary white space. */
padding: 0; /* Padding zero is used to prevent unnecessary white space. */
}        
html, body {
height: 100%;
max-height: 100%;
}
body {
padding: 20px;
}
.page {
border: 1px solid rgb(212, 212, 212);
height: 100%;
max-height: 100%;
padding: 10px;
position: relative;
}
#confirm > p {
padding-bottom: 20px;
}
.k-button {
cursor: pointer;
}
.k-window-titlebar, .k-window-titlebar > span {
cursor: move;
font-weight: bold;
}
</style>
</head>
<body>
<div class="page">
<button class="k-button" data-bind="click: onShowClick">Show confirm</button>
<div id="confirm"></div>
</div>
<script type="text/x-kendo-template" id="confirmTemplate">
<p>#= ConfirmText #</p>
<button class="k-button" id="yesButton">Yes</button>
<button class="k-button" id="noButton"> No</button>
</script>
<!-- Libraries -->
<script type="text/javascript" src="//code.jquery.com/jquery-1.9.1.min.js"></script>
<script type="text/javascript" src="//cdn.kendostatic.com/2014.1.528/js/kendo.all.min.js"></script>
<!-- Custom -->
<script type="text/javascript" src="app.js"></script>
</body>
</html>

 

Code

var kendo = kendo || {};
kendo.controller = (function () {
var self = {};
var _vm = null;
var _confirm = null;
var _confirmTemplate = null;
self.show = function () {
_confirm =  $("#confirm").kendoWindow({
title: "Delete record",
visible: false, // The window will not appear before its .open method is called.
width: "230px",
height: "100px",
}).data("kendoWindow");
_confirmTemplate = kendo.template($("#confirmTemplate").html());
_vm = new kendo.data.ObservableObject({
onShowClick: function () {
// Dynamically set some window options.
_confirm.setOptions({
position: {
top: 200,
left: 200
}
});
_confirm.content(_confirmTemplate({ ConfirmText: "Delete record?"}));
_confirm.open();
$("#yesButton").click(function () {
// TODO: Delete record.
_confirm.close();
})
$("#noButton").click(function () {
// User cancelled the window.
_confirm.close();
})
}
});
kendo.bind($(".page"), _vm);
};
return self;
})();
kendo.controller.show();

How to pass extra / additional parameters to the deferred.then()function in jQuery, $q (AngularJS) or Q.

 

Q or $q

If you are using Q or $q you can pas extra data to the then function by using the $q.all function:

function execute()
{
var firstNames = ['Bo', 'Cris', 'Richard'];
$q.all({
firstNames: $q.when(firstNames),
lastNames: $http.get('/api/lastNames')
}).then(handleGetLastNamesResult)
}
function handleGetLastNamesResult(data)
{
var firstNames = data.firstNames;
var lastNames = data.lastNames;
}

 

jQuery

 

In this example I will use jQuery, but the same pattern works for $q and Q.

You can make an Ajax request in jQuery like, so:

var app = (function ()
{
var self = {};
self.handleGetResult = function (data) {
// Do something with the result from the server.
};
self.start = function ()
{
var promise = $.ajax({
url: 'https://api.github.com/users/roelvanlisdonk/repos',
type: 'GET'
});
$.when(promise).then(self.handleGetResult);
};
self.start();
return self;
})();

The function passed to the .then function can only contain one parameter and will contain the data returned form the server. If you want to pass the function called by the “.then” function some additional data. You can use the following pattern:

 

var app = (function ()
{
var self = {};
self.handleGetResult = function (data) {
var resultHandler = this;
var additionalData = resultHandler.getAdditionalData();
// Do something with the result from the server and the additional data.
};
self.ResultHandler = function (additionalData, handleResultFunc) {
var self = this;
var _additionalData = additionalData;
var _handleResultFunc = handleResultFunc;
self.getAdditionalData = function () {
return _additionalData;
};
self.handleResult = function (data) {
_handleResultFunc.call(self, data);
};
return self;
};
self.start = function ()
{
var promise = $.ajax({
url: 'https://api.github.com/users/roelvanlisdonk/repos',
type: 'GET'
});
var handler = new self.ResultHandler("Some extra data", self.handleGetResult);
$.when(promise).then(handler.handleResult);
};
self.start();
return self;
})();

How to display a message, when a Kendo UI MVVM grid is empty.

If you want to show an text in a Kendo UI grid, you could use CSS, as suggested on stackoverflow.com:

http://stackoverflow.com/questions/23476978/display-a-message-within-the-kendo-grid-when-its-empty

 

But if you want to completely hide the gird and show a message, you can use a calculated field:

http://docs.telerik.com/kendo-ui/getting-started/framework/mvvm/observableobject#creating-dependent-methods-also-known-as-calculated-fields

 

image

 

HTML

<!DOCTYPE html>
<html>
<head>
<title>Kendo element binding research page.</title>
<link rel="stylesheet" type="text/css" href="//cdn.kendostatic.com/2014.1.528/styles/kendo.common.min.css" />
<link rel="stylesheet" type="text/css" href="//cdn.kendostatic.com/2014.1.528/styles/kendo.rtl.min.css" />
<link rel="stylesheet" type="text/css" href="//cdn.kendostatic.com/2014.1.528/styles/kendo.metro.min.css" />
<link rel="stylesheet" type="text/css" href="//cdn.kendostatic.com/2014.1.528/styles/kendo.metro.mobile.min.css" />
    <style>
/* Resets */
div, span, i, p, input, select {
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box; /* Border boxing is used, so the padding, margin and borders are within the width and height of de element. */
color: rgb(112, 112, 112);
font-family: Arial, Helvetica, sans-serif; /* For know use default fonts used on google.com stackoverflow.com, telerik.com etc. */
font-size: 13px;
margin: 0; /* Margin zero is used to prevent unnecessary white space. */
padding: 0; /* Padding zero is used to prevent unnecessary white space. */
}        
html, body {
height: 100%;
max-height: 100%;
}
body {
padding: 20px;
}
.info {
border: 1px solid rgb(128, 128, 128);
box-shadow: rgba(0, 0, 0, 0.298039) 0 2px 6px 0, rgba(0, 0, 0, 0.2) 0 -3px 8px 0;
padding: 10px;
}
.no-data {
border: 1px solid #dadada;
padding: 10px;
}
</style>
</head>
<body>
<div id="view">
<div class="info">            
<script id="productsRowTemplate" type="text/x-kendo-tmpl">
<tr data-uid="#: uid#">
<td>#: Id#</td>
<td>#: Name#</td>
</tr>
</script>
<div id="productsGrid" data-role="grid"
data-row-template="productsRowTemplate"
data-columns="[
{ 'field': 'Id' },
{ 'field': 'Name' }
]"
data-bind="source: products, invisible: productsIsEmpty"></div>
<div class="no-data" data-bind="visible: productsIsEmpty">No data.</div>
</div>
</div>
<!-- Libraries -->
<script type="text/javascript" src="//code.jquery.com/jquery-1.9.1.min.js"></script>
<script type="text/javascript" src="//cdn.kendostatic.com/2014.1.528/js/kendo.all.min.js"></script>

<!-- Custom -->
<script type="text/javascript" src="kendo-controller.js"></script>
</body>
</html>

 

JavaScript

var kendo = kendo || {};
kendo.controller = (function () {
var self = {};
var _vm = null;
self.show = function () {
_vm = new kendo.data.ObservableObject({
products: new kendo.data.DataSource({
data: new kendo.data.ObservableArray([
])
}),
productsIsEmpty: function () {
return this.get("products").data().length === 0;
}
});
kendo.bind($("#view"), _vm);
};
return self;
})();
kendo.controller.show();