|

AngularJS is a modern JavaScript framework that allows creating rich client-side apps in a fast and productive way. It goes without saying that AngularJS is convenient and powerful in working with HTML. However, it doesn’t have ready to use complex UI components yet. In this article we’ll try to partially eliminate this drawback by showing how to add support of dhtmlxScheduler, a Google-like event calendar, for an AngularJS app.

Download dhtmlxScheduler to add a powerful event calendar to your app







You can check the online demo of a ready app or just grab the sources of the app from GitHub.

Adding dhxScheduler Directive



In order to build a custom HTML component in AngularJS we need to create a new directive. So let’s start integrating the Scheduler from writing a directive for it. For this purpose we need to create a .js file with the following content:

app. directive ( 'dhxScheduler' , function ( ) {

return {

restrict : 'A' ,

scope : false ,

transclude : true ,

template : '<div class="dhx_cal_navline" ng-transclude></div><div class="dhx_cal_header"></div><div class="dhx_cal_data"></div>' ,



link : function ( $scope , $element , $attrs , $controller ) {

//adjust size of a scheduler

$scope.$watch ( function ( ) {

return $element [ 0 ] . offsetWidth + "." + $element [ 0 ] . offsetHeight ;

} , function ( ) {

scheduler. setCurrentView ( ) ;

} ) ;



//styling for dhtmlx scheduler

$element. addClass ( "dhx_cal_container" ) ;



//init scheduler

scheduler. init ( $element [ 0 ] , new Date ( ) , "month" ) ;

}

}

The above code may look a bit complicated, but the things the code produces are rather simple:

the code defines a new directive which can be used as a custom attribute

when the new directive (dhxScheduler) is initialized, it will create the dhtmlxScheduler object with the default settings

the watcher function will be constantly checking the size of scheduler’s container and will resize the component when the size of HTML container changes.



For creating an instance of dhtmlxScheduler on a page it’s actually enough to write the above code and place the directive somewhere on the page. If we want to create a simple app with a scheduler inside, the HTML code structure shown below is needed:

<!doctype html>

< html lang = "en" ng-app = "schedulerApp" >

< head >

< meta charset = "utf-8" >

< title > Angular Calendar demo < / title >



< link rel = "stylesheet" href = "css/app.css" >

< link rel = "stylesheet" href = "https://cdn.dhtmlx.com/scheduler/edge/dhtmlxscheduler.css" >

< script src = "https://cdn.dhtmlx.com/scheduler/edge/dhtmlxscheduler.js" >< / script >

< script src = "https://ajax.googleapis.com/ajax/libs/angularjs/1.6.7/angular.min.js" >< / script >



< script src = "js/app.js" >< / script >

< / head >

< body >

< div dhx-scheduler style = "height:350px; width:600px;" >

< div class = "dhx_cal_prev_button" > < / div >

< div class = "dhx_cal_next_button" > < / div >

< div class = "dhx_cal_today_button" >< / div >

< div class = "dhx_cal_date" >< / div >

< div class = "dhx_cal_tab" name = "day_tab" >< / div >

< div class = "dhx_cal_tab" name = "week_tab" >< / div >

< div class = "dhx_cal_tab" name = "month_tab" >< / div >

< div >

< / body >

< / html >

As you can see, we’ve included the .js and .css files of both the AngularJS framework and the dhtmlxScheduler component. Our newly created dxhScheduler directive is used in the code of the page. The dhx-scheduler attribute is used to trigger the directive and to initialize the scheduler component. The HTML tags inside of dhx-scheduler div container are necessary to define the buttons on the top bar of the scheduler.

When you open a page with the described HTML code in a browser, you will see an event calendar component ready to be used:







Linking to the Scope



For now our AngularJS event calendar just renders itself, which is good but not quite useful yet. Let’s link the scheduler’s state and content to the scope in order to expand the app’s functionality. For this purpose we need to extend the link method of the directive as follows:

link : function ( $scope , $element , $attrs , $controller ) {

//default state of the scheduler

if ( ! $scope. scheduler )

$scope. scheduler = { } ;

$scope. scheduler . mode = $scope. scheduler . mode || "month" ;

$scope. scheduler . date = $scope. scheduler . date || new Date ( ) ;



//watch data collection, reload on changes

$scope.$watch ( $attrs. data , function ( collection ) {

scheduler. clearAll ( ) ;

scheduler. parse ( collection , "json" ) ;

} , true ) ;



//watch mode and date

$scope.$watch ( function ( ) {

return $scope. scheduler . mode + $scope. scheduler . date . toString ( ) ;

} , function ( nv , ov ) {

var mode = scheduler. getState ( ) ;

if ( nv. date != mode. date || nv. mode != mode. mode )

scheduler. setCurrentView ( $scope. scheduler . date , $scope. scheduler . mode ) ;

} , true ) ;



//size of scheduler

$scope.$watch ( function ( ) {

return $element [ 0 ] . offsetWidth + "." + $element [ 0 ] . offsetHeight ;

} , function ( ) {

scheduler. setCurrentView ( ) ;

} ) ;



//styling for dhtmlx scheduler

$element. addClass ( "dhx_cal_container" ) ;



//init scheduler

scheduler. init ( $element [ 0 ] , $scope. scheduler . date , $scope. scheduler . mode ) ;

}

Let’s see what was added. The top block checks if there are settings for the scheduler in the scope. If there are no such settings, they will be created with default values.

After the top block, two new watch instructions follow. The first instruction will monitor the state of data collection and reload the scheduler with new data when the collection is changed. The second instruction will change the scheduler’s settings (mode and date) when the related parameters are changed in the scope.

Finally, we have slightly adjusted the scheduler.init command. Now it uses values from the scope as initial view and date values.

After applying all these changes we can do the following:

We can place custom buttons on the page. Clicking the first button will change the displayed date and clicking the second button will switch the mode of events view in the calendar:

< button ng - click = "scheduler.setCurrentView(null, 'week')" > Week </ button >

< button ng - click = "scheduler.setCurrentView(new Date())" > Week </ button >

We can load data from the scope to the scheduler:

app. controller ( 'MainSchedulerCtrl' , function ( $scope ) {

$scope. events = [

{ id : 1 , text : "Task A-12458" ,

start_date : new Date ( 2018 , 09 , 30 , 9 , 0 ) ,

end_date : new Date ( 2018 , 09 , 30 , 16 , 0 ) } ,

{ id : 2 , text : "Task A-83473" ,

start_date : new Date ( 2018 , 09 , 28 , 9 , 0 ) ,

end_date : new Date ( 2018 , 09 , 30 , 16 , 0 ) }

] ;



} ) ;



< div dhx - scheduler data = "events" style = "height:350px; width:600px;" >

We can use some input on the page to filter the scheduler:

< div dhx - scheduler data = "events | filter:search" style = "height:350px; width:600px;" >



Thus we have a scheduler populated with data. The scheduler has the functions of date and mode changing, and data filtering. Next we can customize the appearance of events in the scheduler.

The Look of Events



Well, we can now define the content and appearance of event bars in the calendar. dhtmlxScheduler provides JavaScript API for templating and we can take the advantage of this API to specify the look of events in our calendar. The code below will define one more directive which can be used to define the scheduler’s templates:

app. directive ( 'dhxTemplate' , [ '$interpolate' , function ( $interpolate ) {



return {

restrict : 'AE' ,

terminal : true ,



link : function ( $scope , $element , $attrs , $controller ) {

$element [ 0 ] . style . display = 'none' ;



var htmlTemplate = $interpolate ( $element. html ( ) ) ;

scheduler. templates [ $attrs. dhxTemplate ] = function ( start , end , event ) {

return htmlTemplate ( { event : event } ) ;

} ;



}

} ;

} ] ) ;

This code defines the dhxTemplate directive. This directive can be used both as an attribute or as a custom tag. The content of the directive will be converted to JavaScript function and used as a template of the scheduler. To specify the template for the scheduler, you can use the native AngularJS templates. This syntax implies the use of the {{event.property}} expressions as placeholders in the template’s text.

For example, we can add the following code on the page:

< div dhx - template = "event_bar_text" >

< strong > # { { event. id } } </ strong >: { { event. text | uppercase } }

</ div >

The above code will produce the result as follows:







The dhx-template attribute’s name (“event_bar_text” ) is the name of scheduler’s template which needs to be defined. Check the full list of templates in the documentation.

Take into account the following points:

You need to use the format of the type {{event.some}} to define the template. Instead of “some” place the necessary property of event object. “event.” in our example is a fixed part that is used only by the scheduler to define the event’s property. It is not related to the current scope.

You can’t use the scope’s variables inside of the template.

Summing Up



So although there are no complex UI components in Angular JS, we can add such a component with the help of some additional code. Thus, by using the two directives defined above (dhxScheduler and dhxTemplate) you can easily add a rich-featured event calendar on the page and customize its appearance.

The above described functionality of the scheduler component is just a tip of the iceberg. dhtmlxScheduler has a rich API and lots of properties and events. It makes no sense to wrap all of them into AngularJS directives, as you can easily make any necessary calls from Angular controller’s code (check the details of the dhtmlxScheduler API in the documentation).

The simplicity of integration shows the flexibility of both AngularJS and dhtmlxScheduler. While both of them are independent solutions, with a bit of glue code they work together in a neat way. By using the above code you can get a Google-like event calendar for your AngularJS web app.