3/22/13

Dynamic tabs with knockoutjs - part 3

Gettig all the widgets to work together
Now lets make some slight modifications to tabsViewModel so it will be able to host
the widgets from previous post:

var tabViewModel=function(title, active, model, templateName){ 
  this.title=ko.observable(title);
  this.active=ko.observable(active);
  this.model=ko.observable(model);
  this.templName=templateName;
};
var tabsViewModel=function(){  
  this.tabsArr=ko.observableArray([]); 

 
  this.makeTabActive=function(data){

    
      $.each(this.tabsArr(),function(ind,item){
       item.active('');
   });


   
     data.active('active');
  
  }.bind(this);
  

  this.addTab=function(title, active, model, template){
    var nt=new tabViewModel(title, active, model, template);
 this.tabsArr.push(nt);
    this.makeTabActive(nt);
  }.bind(this);


Only difference is that now there is new parameter inside tab model constructor -the model.
Here we sending the widget that will reside in the tab .

Changing templates
Also templates for tabs must be changed for be able to support model parameter:






Adding functions to each of the widgets:
Each widget must be able now to connect with tabs widget and with other 'brother' widgets inside tabs:

//for add the search tab
homeViewModel.prototype.openSearchTab=function(){
   tabs.tabsArr.push(new tabViewModel('search','' ,new searchViewModel(),'searchTmpl'))
};
//for add the person tab
searchViewModel.prototype.openPersonTab=function(data){

   var f=data.firstname;
   var l=data.lastname;
   var newPerson=new personViewModel(f,l);
   tabs.addTab(f+' '+l,'' ,newPerson,'personTmpl');
};
//for make new friend to appear the home tab
personViewModel.prototype.addFriend=function(){
   var homeVM=tabs.tabsArr()[0].model();
   homeVM.friends.push({name:this.firstname()})
}


Thats it, now our tabbed social network application is ready and functioning.
Hope you enjoy to read this post...
download source
demo

Dynamic tabs with knockoutjs - part 2

Creating 3 simple different widgets
In this post we will create a 3 simple widgets which will be hosted inside the tabs.

Home widget
This widget shows the friends collection, and able to open search page.
Model:

var homeViewModel=function(){  
  this.typename='home';    
  this.templName='homeTmpl';
  this.friends=ko.observableArray([{name:'Shlomo'}]) 
};
View:

<script id="homeTmpl" type="text/html">
 <h3>
  wellcome to Social Network!</h3>
 <b>friends: </b> <hr/>
   <ul data-bind="foreach:friends">
   <li data-bind="text:name"></li> </ul> <div> Wanna find more friends? <button data-bind="click:openSearchTab"
>click here</button><
 /div> </script> <!--ko template: { name: 'homeTmpl' }--><!--/ko-->
demo
Search widget
This widet must show the search engine:
To simplify the functionality, our search may find only to persons:
Vasia and Kolia

Model:

var searchViewModel=function(){
  
  this.typename='search';  
  var that=this;
  this.results=ko.observableArray([]);
  this.searchterm=ko.observable();

  this.clickSearch=function(){
  
    this.results([]);//empty the results array 
    switch(that.searchterm()){   
      case 'k':
        this.results.push({firstname:'Kostia',lastname:'Baranov'});
        break;
      case 'v':    
        this.results.push({firstname:'Vasia',lastname:'Kozlov'});
        break;
   default :
     this.results.push({firstname:'Vasia',lastname:'Kozlov'});
  this.results.push({firstname:'Kostia',lastname:'Baranov'});
    }
  };
  
  
  this.templName='searchTmpl';
};

View:

  <script id="searchTmpl" type="text/html">
    <div data-bind="text:typename">
    </div>
    <input data-bind="value:searchterm" />
    <button class="o" data-bind="click:clickSearch">press</button>

    <table data-bind="foreach:results" class="results">
      <tr>
        <td data-bind="text:firstname,click:$parent.openPersonTab"></td>
      </tr>
    </table>
    </div>
  </script>

demo
Person widget
This widget must show the person details and be able to add this person to friends
array:

Model:


var personViewModel=function(firstname,lastname){
  var that=this;
  this.firstname=ko.observable(firstname);
  this.lastname=ko.observable(lastname);


  this.templName="personTmpl";  
}
View:


  <script id="personTmpl" type="text/html">
    <section class="person"> <img src="img/placeholder.png" alt="pic" />
      <div> <b>first name:</b>
        <label data-bind="text:firstname"></label>
      </div>
      <div> <b>last name:</b>
        <label data-bind="text:lastname"></label>
      </div>
      <button data-bind="click:addFriend">add as friend</button>
    </section>
  </script>
  <!--ko template: { name: 'personTmpl', data: person }-->
  <!--/ko-->
demo
you can download source from github
Now that all 'insider' widgets are ready - we can proceed to the next step

Dynamic tabs with knockoutjs - part 1

Create a simple tabs widget with knockoutjs
Since we dealing with OOP javascript application we gonna use the knockoutjs library which is a very good framework for representing business objects in HTML.

First lets take care of html (view):

<script id="tabLinkTmpl" type="text/html">
<li data-bind="attr:{class:active},text:title,click:$parent.makeTabActive"></li>
</script>
<script id="tabPanelTmpl" type="text/html">
    <div class="content" tab="tab1" data-bind="visible: active()!='',html:content">
     
    </div>
</script>


  <ul class="tabs">
        <!--ko template: { name: 'tabLinkTmpl', foreach: tabsArr }--><!--/ko-->
  </ul>
<div class="contentWrap">
<!--ko template: { name: 'tabPanelTmpl', foreach: tabsArr }--><!--/ko-->
  </div>
<button data-bind="click:function(){ addTab('tab'+tabsArr().length,'','tabs count:'+tabsArr().length) }">Add New Tab</button>
   

Explanation:

For loading tab links and panels i'm using here templates. Templates are HTML code which is rendered by javascript and populated with data from business objects- View Models.
Speaking about View Models - here is the code of tabsViewModel:


var tabViewModel=function(title, active, content){ 
 this.title=ko.observable(title);
 this.active=ko.observable(active);
 this.content=ko.observable(content);
};
var tabsViewModel=function(){  
  this.tabsArr=ko.observableArray([]); 
  this.makeTabActive=function(data){
     //make all the tabs unactive
     $.each(this.tabsArr(),function(ind,item){
       item.active('');
  });
     //activate current tab  
     data.active('active');  
  }.bind(this);
  
  
  this.addTab=function(title, active, content){
    var nt=new tabViewModel(title, active, content);
 this.tabsArr.push(nt);
    this.makeTabActive(nt);
  }.bind(this);
};
var tabs=new tabsViewModel();
tabs.addTab('home','active', 'This is a home tab')
ko.applyBindings(tabs);


Explanation:
The tabs functionality includes two View Models: The tabViewModel - which represents the single tab entity, and tabsViewModel which responsible of managing all the tabs (like activating, creating etc)

At the result you get the knockoutjs based tabs widget:

you can download source from github
or see demo
Now, after we created functioning tabs widget -we ready to go to the next step

Dynamic tabs with knockoutjs - introduction

There is many beautifull javascript tabs-widget examples across the web, many of them fit perfectly for the regular scenarios of displaying static or dynamic content. When talking about dynamic content - it usually means that objects which showed in each tab is from the same type, only the quantity of tabs may vary. (like this example - each tab must have the same structure of header and content).
In this post i will demonstrate how to create tabs widget where each tab is represent a different kind of javascript module, which act independently and in coexistence with other tabs-modules.



i decided to divide this post to 4 parts (so it will be more convenient to read) 
introduction - the Social Netwok app 
part 1 - create a simple tabs widget with knockoutjs (next post)
part 2 - create  3 viewModels for each kind of tabs (next next post)
part 3 - get all the stuff to work together (next next next post)

So here is the first part:


the Social Netwok app - the spec
Lest say we want to create social network, with 'search-firends' page, 'display person details' page and 'home' page, only instead of pages - each view will be displayed on different tab panel:
home:

search:

person details:
To achieve this goal we will need to define 3 kind of different javascript functionalities - one for each page/tab:  'Search' -must be able to perform the  persons search, 'home' -must display the friends list, and 'person details' -must display details of person and to add this person to the friend list which appears on the 'home' page.
Expect of acting independently each functionality must at the same time to connect with other 'brothers' (like add person to friends list)   and to connect with the tabs widget - (like open search view inside tab).

Note that in some cases tabs should be able to contain multiple instances of objects from same type- like two persons...

I hope you enjoyed reading this post so far
so if you want to continue - here is the next part 

3/17/13

How to extend jquery ui widget

Sometimes it is happen that you need to use some jquery ui widget, which is perfect solution for your project except one little feature - that must be somehow act differently. In that case some customization of the widget needed. As you may already know - in javascript, it may be plenty of ways to do the same thing, the question is - what is the nicest way. In this post i will try to show some ways of widget customization and discus the advantages/disadvantages of each way.

For example we will take the jquery ui dialog widget. Lets say in your project you must have the same  dialogs as jquery ui offers, but without the titlebar :

Of course, in real life the things to change would be much more interesting and complicate, the dialog titlebar is only using us for making the example easier.
So, you can handle this in some quick way like using the "open" event of the plugin:

$( "#dialog" ).dialog({
    modal:true,
    open:function(){
       $(this).parent().find(".ui-dialog-titlebar").hide();
    }
}) 

This will work, but what if we using the same kind of dialog in multiple places? In this case you will need to specify the same open handler code each time you make use the of dialog widget.
More convenient way to make all dialog insitances to hide titlebar at once- is to make a little modifictaion inside the code of the widget.
You can download the full source code of all jquery ui widgets from the githube repository and play with the code as you wish. Once you clicked the ZIP button

all the code is yours. You can find the dialog widget code inside ui folder -here is it jquery.ui.widget.js.
So desired functionality can easily be achieved if we comment out the following line inside _create method:



var uiDialogTitlebar = (self.uiDialogTitlebar = $('<div>
</div>'))

 .addClass(
  'ui-dialog-titlebar ' +
  'ui-widget-header ' +
  'ui-corner-all ' +
  'ui-helper-clearfix'
 )
 /*.prependTo(uiDialog)*/,

This code creating the titlebar element and adds it to dialog body.
Comment it out will make all the dialogs to appear without titlebars in all the places, as needed.
Unfortunately, short time after the brilliant solution you found it may occur that the application design will change so that in some lonely case the dialog titlebar will be still needed.

extending dialog widget
For this case, i think  you may take advantage of the $.widget method generously offered by jquery-ui framework.The method give you an ability to create your own custom dialog widget that inherits form the standart jquery-ui module:



$.widget('ui.extendeddialog', $.ui.dialog, {
 _init: function() {
  if ( this.options.autoOpen ) {
   this.open();
  }
  //hiding the titlebar  
         this.uiDialogTitlebar.hide();
 }
});     

Explanation: In this code i make the new widget named extendeddialog, which is exact copy of jquery-ui dialog except -that it has no titlebar. I choose to override the _init method that runs after all the elements of the widget been created already in previously called _create method.
Now if you need to display dialogs without titlebars you may use the new extended widget ,which should called in  following way:


$( "#dialog" ).extendeddialog();

The original dialog widget is functioning now without changes.
$( "#dialog1" ).dialog();

You may be noticed the code inside init method that does not contribute a thing to hiding titlebar functionality:

if ( this.options.autoOpen ) {
 this.open();
}
This code must stay inside the _init method because we overriding it when we specify it inside $.widget function parameter. So here is the way the widget extending code may be more nice: instead of coping all the code of overriden function - we may call the original function of the original widget (prototype) from inside the overriding code:

$.widget('ui.extendeddialog', $.ui.dialog, {
  _init: function() {
    //calling the _init function of prototype  (like "super" in java)
    $.ui.dialog.prototype._init.call(this);
    //hiding the titlebar
    this.uiDialogTitlebar.hide();
  }
});
Now it much more nice.
We can augment our new extendeddialog widget even little bit more: We can add the ability to hide the titlebar conditionally(depend on hideTitle custom option):

 $.widget('ui.extendeddialog', $.ui.dialog, {
 _init: function() { 
  $.ui.dialog.prototype._init.call(this);
  if( this.options.hideTitle )this.uiDialogTitlebar.hide();
 },
        //extending the options
 options : {
              hideTitle:true 
 }
});
From now if we give hideTitle option the false value( by default it is true) - the titlebar will become visible.

$( "#dialog" ).extendeddialog({hideTitle:false});
Hope this post was interesting,
I wish it will help somebody to  understand things better...

Getting started with docker

It is very simple to get started usig docker. All you need to do-is download the docker desktop for your system Once you get docker syste...