Websites QNH

Techblog Lingual

Main media

Contents

  1. Introduction
  2. Connect
  3. Transactions
  4. Indices
  5. Cursor
  6. Performance
  7. Conclusion
  8. Resources

1. Introduction

Today many ways exist to store data inside a browser. What started with cookies has now evolved to very comprehensive storage mechanisms. Web Storage (LocalStorage/SessionStorage) is a key-value store which can hold up to 5MB of data. Web SQL brings SQL to the frontend and can store significantly more data. Although WebSQL is widely supported, the W3C dropped support because it was not a standard, but an implementation of SQLite.

The alternative for Web SQL is the Indexed Database API (IndexedDB), developed by the Mozilla foundation, a NoSQL database which stores key-values. The values can be complex structured objects and keys can be properties of those objects.

Below we will explore this next-gen storage mechanism where I will show how to persist this ‘customerData’ object

1
2
3
4
customerData=[
        {ssn:"444-44-4444",name:"Bill",age:35,email:"bill@company.com"},
        {ssn:"555-55-5555",name:"Donna",age:32,email:"donna@home.org"}
      ];

Please note that at this moment firefox is the only browser fully supporting all the specs of IndexedDB.

Connect

To setup a connection with an IndexedDB database you have to use the IndexedDB object. However, it is still an experimental feature and therefore hidden under browser prefixes. The following code snippet shows how to setup a connection and which events to listen to

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
var indexedDB = window.indexedDB   || window.webkitIndexedDB ||
                window.mozIndexedDB|| window.msIndexedDB ;

var dbconn = indexedDB.open("mydb",1) ; // 1 is the version number

dbconn.onerror = function(event) {
  // Do something with dbconn.errorCode! 
};
dbconn.onsuccess = function(event) {
  // read and/or write to objectStores
}
dbconn.onupgradeneeded = function(event) {
  // Update object stores and indices 
}

Binding to these events is necessary, because this process is asynchronous. The onupgradeneeded event is special and is only fired when the database is created or the version number has changed. Inside this function you can create/modify the tables, which are called ‘object stores’. For the ‘customerData’ object we could create the following object store

1
2
3
4
5
var db = event.target.result ;

var objectStore = db.createObjectStore( "customers",{keyPath:"ssn"}) ;
objectStore.createIndex("name","name",{unique:false});
objectStore.createIndex("email","email",{unique:true});

‘ssn’ and ‘email’ should be unique, and with the keyPath option the ‘ssn’ value is used as the key. Indices are useful because they can be used for searches.

Transactions

Within a transaction you can read from, write to and delete entries from an object store. Furthermore a transaction has a scope: the objects stores it applies to, and a mode: read only or read-write. So, to write the customerData to the customers store do

1
2
3
4
5
6
var trans = event.target.result.transaction(['customers'], IDBTransaction.READ_WRITE) ;

var objectStore = trans.objectStore('customers') ;
for( var i in customerData ) {
    objectStore.add(customerData[i]) ;
}

An entry lookup by its key value is equally simple

1
2
3
4
5
6
7
8
var trans = event.target.result.transaction(['customers'], IDBTransaction.READ) ;

var objectStore = trans.objectStore('customers') ;
var result = objectStore.get('444-44-4444') ; 

result.onsuccess = function(e) {
     alert("Name for SSN 444-44-4444 is " + r.result.name);
}

Instead of using the event.target.result you can use dbconn.result, which is useful when performing any of these actions outside the dbconn.onsuccess function.

1
var trans = dbconn.result.transaction(['customers'], IDBTransaction.READ) ;

Indices

Using an index is basically identical to a lookup by its key value. The only practical difference is that an index doesn’t have to be unique, in which case the entry with the lowest key value is returned

1
2
3
4
5
// Assume a transaction and object store object exist
var index = objectStore.index("name");
index.get("Donna").onsuccess = function(event) {
  alert("Donna's SSN is " + event.target.result.ssn);
};

Cursors

With a cursor you can retrieve one or more entries. For example, if the above example would normally return multiple entries a cursor could be used as follows

1
2
3
4
5
6
7
8
var boundKeyRange = IDBKeyRange.only("Donna");
index.openCursor(boundKeyRange).onsuccess = function(event) {
  var cursor = event.target.result;
  if (cursor) {
    alert("Name: " + cursor.key + ", SSN: " + cursor.value.ssn + ", email: " + cursor.value.email);
    cursor.continue();
  }
};

With the IDBKeyRange you can also define a lower and upper bound, which allows you to retrieve a range of entries

1
2
//Match anything between "Bill" and "Donna", but not including "Donna" 
var boundKeyRange = IDBKeyRange.bound("Bill", "Donna", false, true);

Performance

To get an idea about the performance I have written a performance test for WebSQL and IndexedDB. Testing with 500000 entries the only noticable difference is that IndexedDB is a lot faster with inserts. This is because it builds its indices afterwards. Only during this period the performance is not very good, but when this process is finished, it performs equally well as WebSQL.

Conclusion

IndexedDB is a very robust and well performing alternative to WebSQL, but unfortunately still experimental. The fact that Firefox and Internet Explorer have no plans to support WebSQL, will speed up the adoption of IndexedDB.

Resources

Deel dit artikel:
  • Facebook
  • Yahoo! Buzz
  • Twitter
  • Google Bookmarks
  • Hyves
  • LinkedIn

In mijn huidige project werken we veel met Sharepoint. Om inzicht en overzicht te verkrijgen in de hele farm gebruiken we sinds kort de tool SharePoint Manager 2007. Intussen is er ook een 2010 versie. Met SharePoint manager krijg je o.a. inzicht in:

- Farm setting
- Farm servers
- Web App overview
- Web App on server
- Central admin options
- Definitions export (list, content type)
- Account Security overview

Download SharePoint Manager via CodePlex: http://spm.codeplex.com/releases/22762/download/57473

Deel dit artikel:
  • Facebook
  • Yahoo! Buzz
  • Twitter
  • Google Bookmarks
  • Hyves
  • LinkedIn

Voor een project heb ik de volgende functie gebruikt die een comma seperated string (bijvoorbeeld “1,5,7,14″) omzet naar een tabel. Met als resultaat:

SELECT * FROM StringToTable ('1,5,7,14')

number
1
5
7
14

Uitwerking:

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author: Marc van Heugten
-- Create date: 2012-02-28
-- Description: Returns a table for a given string (e.g. 1,4,7,66)
-- =============================================
CREATE FUNCTION StringToTable (@list nvarchar(MAX))
RETURNS @tbl TABLE (number int NOT NULL) AS
BEGIN
DECLARE @pos int,
@nextpos int,
@valuelen int

SELECT @pos = 0, @nextpos = 1

WHILE @nextpos > 0
BEGIN
SELECT @nextpos = charindex(',', @list, @pos + 1)
SELECT @valuelen = CASE WHEN @nextpos > 0
THEN @nextpos
ELSE len(@list) + 1
END - @pos - 1
INSERT @tbl (number)
VALUES (convert(int, substring(@list, @pos + 1, @valuelen)))
SELECT @pos = @nextpos
END
RETURN
END
Deel dit artikel:
  • Facebook
  • Yahoo! Buzz
  • Twitter
  • Google Bookmarks
  • Hyves
  • LinkedIn

Very often when a webpage is built, CSS is not given the attention it deserves. Having your CSS well structured, maybe with the help of sass, will definitely boost development and improve maintainability. But thats not all, to develop faster, good knowledge of CSS is essential. Simple problems can give headaches to developers unaware of the CSS ins-and-outs.

Collapsing Margins is definitely one of CSS’s strangest behaviors, and very likely to occur. Checkout this example:

No vertical margins, only the outer element has a 10px margin. What happens is that when two vertical margins (top or bottom) touch, only the largest margin is used and given to the first/outer element. The margins are only summed when one has a negative value.

If this behavior is not desirable, you have to make sure the vertical margins are not adjoining. You can achieve this by doing:

  • floated elements
  • absolutely positioned elements
  • inline-block elements
  • elements with overflow set to anything other than visible (They do not collapse margins with their children.)
  • cleared elements (They do not collapse their top margins with their parent block’s bottom margin.)
  • the root element
  • adding a border or padding


(Example)
The only thing changed with the previous example is a padding; no touching margins anymore!!

Finally, Internet Explorer ( version 7 and below ) will not collapse margins when the elements have a layout (for example if the elements have a width or height)

Please checkout the Box Model documentation

Deel dit artikel:
  • Facebook
  • Yahoo! Buzz
  • Twitter
  • Google Bookmarks
  • Hyves
  • LinkedIn

Contents

  1. Introduction
  2. $.Class
  3. $.Controller
  4. $.Model
  5. $.View
  6. Conclusion
  7. Resources

1. Introduction

JavaScriptMVC (JMVC) is a frontend development framework based on jQuery. Besides MVC libraries it provides utilities for testing, dependency management and the generation of documentation. With these useful components you will be able to build a maintainable, error-free, lightweight application in the shortest amount of time.

JMVC is divided into the following sub-projects

  • jQueryMX       – a set of jQuery plugins
  • StealJS          - dependency management
  • FuncUnit        - testing framework
  • DocumentJS   – documentation generation

To limit the scope of this article only jQueryMX is discussed, the MVC part of JMVC

jQueryMX is a group of jQuery extensions, the building blocks of MVC. Although these extensions are packaged toghether, you can use them individually too. With the Download Builder you can select the extensions you need.

2 $.Class

This extension simulates class-oriented inheritance, because JavaScript uses a class-free prototype-oriented inheritance approach. To create a class you can use the following syntax

1
$.Class(ClassName,  { /* static members */ }, { /* instance members */ }) ;

 

This is just the basics, it’s real power is inheritance and namespacing

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
$.Class('com.example.Bar', { /* static members */ },  {
      init: function(name){
           this.name = name ;
       },
      toString: function() {
            return this.name ;
       },
});

com.example.Bar('com.example.Foo', { /* static members */ }, {
      toString: function() {
            return this._super() + ' Rocks' ;
       }
}) ;

var obj = new com.example.Foo('JavaScriptMVC') ;
alert(obj.toString()) ; // -> JavaScriptMVC Rocks

( Execute the example )

This is a Class inheritance example, demonstrating function overriding. First the Bar class is created and namespaced with com.example. In complex environments namespaces are crucial, because without them you would pollute your global namespace and risk getting nasty conflicts, with the result of timeconsuming bug hunts.

Furthermore, the Foo class inherits from Bar and overrides the toString method.

3 $.Controller

With $.Controller you can write widgets like sliders, tabs or grids. It simplifies widget development, especially event management; on() and off() are called behind the scene. Take a look at the following example, it shows how easy it is to use events

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
$.Controller('MyTestWidget', { // static members
        count: 0
    }, { // prototype members
        init: function(rawEl, rawOptions) {
            $('.spot:first').clone().html('widget ' + (++this.Class.count))
                                          .appendTo(this.element) ;
        },
        mousemove: function(el, ev) {
           el.css('background-color', 'red') ;
        },
        '{window} .reset click': function(el, ev) {
            this.element.css('background-color', '') ;
        },
        '.spot click': function(el, ev) {
            el.fadeOut().fadeIn() ;
        }
   }) ;

$('.widget').my_test_widget() ;

( Execute the example )

Binding events always apply to elements inside the widget-element. You can change this scoping feature by prepending the event/selector definition by a DOM object surrounded by curly braces (see line 12)

4 $.Model

This extension provides a very powerful and robust data layer, with features like JSON/REST support and the Observable pattern implementation. Here is an example of how to define and use a Model

1
2
3
4
$.Model( 'Todo' ) ; // define the Todo model

var todo = new Todo( { name: 'Bar' } ) ;
todo.save(successHandler, ErrorHandler )

 

Saving the data to a backend is an asynchronious task, so you have to use callback functions. But you can also use the Deferred returned by the save() function. Finally, with the Observable pattern monitoring this Todo model isn’t a big challenge too

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
$.Controller('Todos',{
  "{Todo} created" : function(Todo, ev, todo) {
      // do something 
  }
}) ;

$.Model( 'Todo' ) ;

var todo = new Todo({ name: 'Bar' }) ;
todo.bind('name', function(event, newValue) {
    // do something here too
}) ;

( Demo )

The ‘created’ event is fired when a new Todo instance is created/saved. But a controller can also listen to updated and destroyed events. It is also possible to define your own custom events (see the demo). For attribute changes you bind an event handler to the instance itself (line 10).  

5 $.View

Working with template engines is very powerful, but with $.View it gets even better. For example, the $.View extension overwrites the jquery modifiers so now you can do things like

1
$("#bar").html('atemplate.tmpl',data)

 

With the modifications made by $.View,  the html() modifier loads the template file, executes the template engine and inserts the result. $.View comes pre-packaged with 4 different template engines, which you can choose from using the Download Builder. But $.View uses Deferreds too, so why not load the data at the same time

1
2
3
4
$('#bar').html('atemplate.tmpl',{
  users : User.findAll(),
  todos: Todo.findAll()
})

 

6. Conclusion

This article is far from a complete reference, but consider it a teaser, providing some insights of what JMVC is and can do. The jQueryMX extensions give your application a good maintainable structure and all its features will definitely boost software development. Because of its good structure, this framework perfectly fits together with frameworks that lag this capability. A good example I think would be jQueryMobile.

7. Resources

Deel dit artikel:
  • Facebook
  • Yahoo! Buzz
  • Twitter
  • Google Bookmarks
  • Hyves
  • LinkedIn
© 2011 QNH TechBlog Suffusion theme by Sayontan Sinha