Angular Standalone Smart.Scheduler

Smart.Scheduler as a standalone Angular component

This topic will show you how to use Smart.Scheduler and any other of our components in a combination of the new Angular's feature: standalone components. This feature was a preview in Angular 14 and now in Angular 15, it was introduced as a stable API.

What are standalone components?

The long-awaited feature: standalone components, allow the developer to create a component without declaring it in a NgModule. You can directly import the newly created component into another one. Standalone components can manage their template dependencies alone without NgModule. That reduces the need for NgModule and can make it optional. The goal is to shift the focus from NgModules to Components. A standalone component is marked as standalone with the property standalone: true The dependencies are directly specified in an imports array

Setup Angular Environment

To create new Angular project we need Angular cli:

npm install -g @angular/cli

the -g flag is for global. Once you install it you can use it everywhere, not only in this project.

Create a new project this way:

ng new smart-app

We do not need routing and we will use CSS, so press enter two times

Next navigate to smart-app

cd smart-app
  1. Delete src/app.component.spec.ts

    Delete src/app.module.ts

  2. Remove Everything from src/app.component.html

  3. Convert src/app/app.component.ts to standalone:

    @Component({
      selector: 'app-root',
      standalone: true,
      templateUrl: './app.component.html',
      styleUrls: ['./app.component.css'],
      imports: []
    })
  4. Bootstrap the AppComoponent in the main.ts file:

    // in the main.ts file
    import { bootstrapApplication } from '@angular/platform-browser';
    import { AppComponent } from './app/app.component';
    
    bootstrapApplication(AppComponent);

Setup Smart UI

Smart UI for Angular is distributed as smart-webcomponents-angular NPM package

  • Open the terminal and install the package:
    ng add smart-webcomponents-angular

    The command executes the following actions:

    1. Adds the smart-webcomponents-angular package as a dependency.
    2. Imports the Modules in the current application module.
    3. Registers the default Smart UI theme in the angular.json file.
    4. Adds all required peer dependencies to package.json
    5. Triggers npm install to install the theme and all peer packages that are added.

Import the SchedulerModule

Standalone components can use existing NgModules by directly importing them in the imports array.

To use Smart.Scheduler we should import our SchedulerModule in our application and since we are using a standalone component we will import it into the imports array:

Set the encapsulation to ViewEncapsulation.None for styilization purposes

import the SchedulerModule directly in app.component.ts

import { Component, ViewChild, ViewEncapsulation } from '@angular/core';
import { SchedulerComponent, SchedulerModule } from 'smart-webcomponents-angular/scheduler';

@Component({
  standalone: true,
  selector: 'app-root',
  imports: [SchedulerModule],
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
  encapsulation: ViewEncapsulation.None
})

Initialize Smart.Scheduler

We did everything required to use Smart.Scheduler and it is time to create it:

Open app.component.html and use smart-scheduler component as shown:

<smart-scheduler 
  #scheduler 
  id="scheduler" 
  [dataSource]="dataSource" 
  [view]="view" 
  [dateCurrent]="dateCurrent"
  [views]="views" 
  [hourStart]="hourStart"
></smart-scheduler>

Now you must initialize the properties for the scheduler

Open app.component.ts and import SchedulerViewType

import { SchedulerComponent, SchedulerModule, SchedulerViewType } from 'smart-webcomponents-angular/scheduler';

Paste the following inside the component's class:

export class AppComponent {
  title = 'smart-app';

  @ViewChild('scheduler', { read: SchedulerComponent, static: false }) scheduler!: SchedulerComponent;

  today = new Date();
  
  dataSource = [];

  view: SchedulerViewType = 'agenda';

  dateCurrent: Date = new Date(this.today.getFullYear(), this.today.getMonth(), this.today.getDate(), 9, 0);

  views: object[] = [{ label: 'Agenda', type: 'agenda' }];

  hourStart: number = 9;
}

We will apply the following styles in app.component.css

.smart-scheduler {
  width: 100%;
  height: 100%;
  --smart-scheduler-timeline-cell-height: 60px;
  --smart-scheduler-timeline-weekend-color: var(--smart-background);
  /* Optional. By default weekends are colored */
}

Injecting data service

You may have seen that the scheduler is empty that is happening because in the dataSource we passed an empty array. Now we will create a data service for our scheduler. This will show you how to use dependency injection with the standalone approach

  1. Open the terminal and run
    ng g service data
  2. Delete data.service.spec.ts
  3. Open data.service.ts and replace the
    @Injectable({
      providedIn: 'root'
    })
    with
    @Injectable()
  4. Import the SchedulerEvent
    import { SchedulerEvent } from 'smart-webcomponents-angular';
  5. Add this method inside the class:
    export class DataService {
    
      constructor() { }
    
      GetData(): SchedulerEvent[] {
    
        const today = new Date();
    
        const year = today.getFullYear();
        const month = today.getMonth();
        const date = today.getDate();
    
        return [
          {
            label: 'Google AdWords Strategy',
            dateStart: new Date(year, month, date, 9, 0),
            dateEnd: new Date(year, month, date + 1, 10, 30),
            backgroundColor: '#39BF00',
            allDay: true
          }, {
            label: 'New Brochures',
            dateStart: new Date(year, month, date + 1, 11, 30),
            dateEnd: new Date(year, month, date + 2, 14, 15),
            backgroundColor: '#FFD900'
          }, {
            label: 'Brochure Design Review',
            dateStart: new Date(year, month, date + 2, 13, 15),
            dateEnd: new Date(year, month, date + 4, 16, 15),
            backgroundColor: '#FF0000'
          }, {
            label: 'Website Re-Design Plan',
            dateStart: new Date(year, month, date + 6, 16, 45),
            dateEnd: new Date(year, month, date + 10, 11, 15),
            backgroundColor: '#DADADA'
          },
          {
            label: 'Rollout of New Website and Marketing Brochures',
            dateStart: new Date(year, month, date - 8, 8, 15),
            dateEnd: new Date(year, month, date - 8, 10, 45),
            backgroundColor: '#BF6060'
          }, {
            label: 'Update Sales Strategy Documents',
            dateStart: new Date(year, month, date - 8, 12, 0),
            dateEnd: new Date(year, month, date - 8, 13, 45),
            backgroundColor: '#6D6D6D'
          }, {
            label: 'Non-Compete Agreements',
            dateStart: new Date(year, month, date - 7, 8, 15),
            dateEnd: new Date(year, month, date - 7, 9, 0),
            backgroundColor: '#BF60B2'
          }, {
            label: 'Approve Hiring of John Jeffers',
            dateStart: new Date(year, month, date - 7, 10, 0),
            dateEnd: new Date(year, month, date - 7, 11, 15),
            backgroundColor: '#689F38'
          }, {
            label: 'Update NDA Agreement',
            dateStart: new Date(year, month, date - 7, 11, 45),
            dateEnd: new Date(year, month, date - 7, 13, 45),
            backgroundColor: '#004A80'
          }, {
            label: 'Update Employee Files with New NDA',
            dateStart: new Date(year, month, date - 7, 14, 0),
            dateEnd: new Date(year, month, date - 7, 16, 45),
            backgroundColor: '#7CBF60'
          }, {
            label: 'Submit Questions Regarding New NDA',
            dateStart: new Date(year, month, date - 4, 8, 0),
            dateEnd: new Date(year, month, date - 4, 9, 30),
            backgroundColor: '#BFB160'
          }, {
            label: 'Submit Signed NDA',
            dateStart: new Date(year, month, date - 4, 12, 45),
            dateEnd: new Date(year, month, date - 4, 14, 0),
            backgroundColor: '#BF6089'
          }, {
            label: 'Review Revenue Projections',
            dateStart: new Date(year, month, date - 4, 17, 15),
            dateEnd: new Date(year, month, date - 4, 18, 0),
            backgroundColor: '#0095FF'
          }, {
            label: 'Comment on Revenue Projections',
            dateStart: new Date(year, month, date - 5, 9, 15),
            dateEnd: new Date(year, month, date - 5, 11, 15),
            backgroundColor: '#689F38'
          }, {
            label: 'Provide New Health Insurance Docs',
            dateStart: new Date(year, month, date - 5, 12, 45),
            dateEnd: new Date(year, month, date - 5, 14, 15),
            backgroundColor: '#403600'
          }, {
            label: 'Review Changes to Health Insurance Coverage',
            dateStart: new Date(year, month, date - 5, 14, 15),
            dateEnd: new Date(year, month, date - 5, 15, 30),
            backgroundColor: '#4DFF00'
          }, {
            label: 'Review Training Course for any Ommissions',
            dateStart: new Date(year, month, date - 2, 14, 0),
            dateEnd: new Date(year, month, date - 1, 12, 0),
            backgroundColor: '#60BF96'
          }, {
            label: 'Recall Rebate Form',
            dateStart: new Date(year, month, date - 2, 12, 45),
            dateEnd: new Date(year, month, date - 2, 13, 15),
            backgroundColor: '#BF0052'
          }, {
            label: 'Create Report on Customer Feedback',
            dateStart: new Date(year, month, date - 1, 15, 15),
            dateEnd: new Date(year, month, date - 1, 17, 30),
            backgroundColor: '#00BF6C'
          }, {
            label: 'Review Customer Feedback Report',
            dateStart: new Date(year, month, date - 1, 16, 15),
            dateEnd: new Date(year, month, date - 1, 18, 30),
            backgroundColor: '#3600BF'
          }, {
            label: 'Customer Feedback Report Analysis',
            dateStart: new Date(year, month, date, 9, 30),
            dateEnd: new Date(year, month, date, 10, 30),
            backgroundColor: '#80006E'
          }, {
            label: 'Prepare Shipping Cost Analysis Report',
            dateStart: new Date(year, month, date, 12, 30),
            dateEnd: new Date(year, month, date, 13, 30),
            backgroundColor: '#80006E'
          }, {
            label: 'Provide Feedback on Shippers',
            dateStart: new Date(year, month, date, 14, 15),
            dateEnd: new Date(year, month, date, 16, 0),
            backgroundColor: '#919191'
          }, {
            label: 'Select Preferred Shipper',
            dateStart: new Date(year, month, date, 17, 30),
            dateEnd: new Date(year, month, date, 20, 0),
            backgroundColor: '#BF6089'
          }, {
            label: 'Complete Shipper Selection Form',
            dateStart: new Date(year, month, date + 1, 8, 30),
            dateEnd: new Date(year, month, date + 1, 10, 0),
            backgroundColor: '#BF6060'
          }, {
            label: 'Upgrade Server Hardware',
            dateStart: new Date(year, month, date + 1, 12, 0),
            dateEnd: new Date(year, month, date + 1, 14, 15),
            backgroundColor: '#00BF6C'
          }, {
            label: 'Upgrade Personal Computers',
            dateStart: new Date(year, month, date + 1, 14, 45),
            dateEnd: new Date(year, month, date + 1, 16, 30),
            backgroundColor: '#689F38'
          }, {
            label: 'Upgrade Apps to Windows RT or stay with WinForms',
            dateStart: new Date(year, month, date + 2, 10, 30),
            dateEnd: new Date(year, month, date + 2, 13, 0),
            backgroundColor: '#802049'
          }, {
            label: 'Estimate Time Required to Touch-Enable Apps',
            dateStart: new Date(year, month, date + 2, 14, 45),
            dateEnd: new Date(year, month, date + 2, 16, 30),
            backgroundColor: '#BF60B2'
          }, {
            label: 'Report on Tranistion to Touch-Based Apps',
            dateStart: new Date(year, month, date + 2, 18, 30),
            dateEnd: new Date(year, month, date + 2, 19, 0),
            backgroundColor: '#806C00'
          }, {
            label: 'Submit New Website Design',
            dateStart: new Date(year, month, date + 5, 8, 0),
            dateEnd: new Date(year, month, date + 5, 10, 0),
            backgroundColor: '#6D6D6D'
          }, {
            label: 'Create Icons for Website',
            dateStart: new Date(year, month, date + 5, 11, 30),
            dateEnd: new Date(year, month, date + 5, 13, 15),
            backgroundColor: '#FFB300'
          }, {
            label: 'Create New Product Pages',
            dateStart: new Date(year, month, date + 6, 9, 45),
            dateEnd: new Date(year, month, date + 6, 11, 45),
            backgroundColor: '#BA68C8'
          }, {
            label: 'Approve Website Launch',
            dateStart: new Date(year, month, date + 6, 12, 0),
            dateEnd: new Date(year, month, date + 6, 15, 15),
            backgroundColor: '#9CCC65'
          }, {
            label: 'Update Customer Shipping Profiles',
            dateStart: new Date(year, month, date + 7, 9, 30),
            dateEnd: new Date(year, month, date + 7, 11, 0),
            backgroundColor: '#00ACC1'
          }, {
            label: 'Create New Shipping Return Labels',
            dateStart: new Date(year, month, date + 7, 12, 45),
            dateEnd: new Date(year, month, date + 7, 14, 0),
            backgroundColor: '#689F38'
          }, {
            label: 'Get Design for Shipping Return Labels',
            dateStart: new Date(year, month, date + 7, 15, 0),
            dateEnd: new Date(year, month, date + 7, 16, 30),
            backgroundColor: '#8D6E63'
          }, {
            label: 'PSD needed for Shipping Return Labels',
            dateStart: new Date(year, month, date + 8, 8, 30),
            dateEnd: new Date(year, month, date + 8, 9, 15),
            backgroundColor: '#EF5350'
          }, {
            label: 'Contact ISP and Discuss Payment Options',
            dateStart: new Date(year, month, date + 8, 11, 30),
            dateEnd: new Date(year, month, date + 8, 16, 0),
            backgroundColor: '#B388FF'
          }, {
            label: 'Prepare Year-End Support Summary Report',
            dateStart: new Date(year, month, date + 8, 17, 0),
            dateEnd: new Date(year, month, date + 8, 20, 0),
            backgroundColor: '#FFF176',
            color: '#D81B60'
          }, {
            label: 'Review New Training Material',
            dateStart: new Date(year, month, date + 9, 8, 0),
            dateEnd: new Date(year, month, date + 9, 9, 15),
            backgroundColor: '#C6FF00',
            color: '#5D4037'
          }, {
            label: 'Distribute Training Material to Support Staff',
            dateStart: new Date(year, month, date + 9, 12, 45),
            dateEnd: new Date(year, month, date + 9, 14, 0),
            backgroundColor: '#90CAF9'
          }, {
            label: 'Training Material Distribution Schedule',
            dateStart: new Date(year, month, date + 9, 14, 15),
            dateEnd: new Date(year, month, date + 9, 16, 15),
            backgroundColor: '#7CB342'
          }, {
            label: 'Approval on Converting to New HDMI Specification',
            dateStart: new Date(year, month, date + 12, 9, 30),
            dateEnd: new Date(year, month, date + 12, 10, 15),
            backgroundColor: '#26A69A'
          }, {
            label: 'Create New Spike for Automation Server',
            dateStart: new Date(year, month, date + 12, 10, 0),
            dateEnd: new Date(year, month, date + 12, 12, 30),
            backgroundColor: '#689F38'
          }, {
            label: 'Code Review - New Automation Server',
            dateStart: new Date(year, month, date + 12, 13, 0),
            dateEnd: new Date(year, month, date + 12, 15, 0),
            backgroundColor: '#00B0FF'
          }, {
            label: 'Confirm Availability for Sales Meeting',
            dateStart: new Date(year, month, date + 13, 10, 15),
            dateEnd: new Date(year, month, date + 13, 15, 15),
            backgroundColor: '#A5D6A7'
          }, {
            label: 'Reschedule Sales Team Meeting',
            dateStart: new Date(year, month, date + 13, 16, 15),
            dateEnd: new Date(year, month, date + 13, 18, 0),
            backgroundColor: '#FF6E40'
          }, {
            label: 'Send 2 Remotes for Giveaways',
            dateStart: new Date(year, month, date + 14, 9, 30),
            dateEnd: new Date(year, month, date + 14, 11, 45),
            backgroundColor: '#FFD54F'
          }, {
            label: 'Discuss Product Giveaways with Management',
            dateStart: new Date(year, month, date + 14, 12, 15),
            dateEnd: new Date(year, month, date + 14, 16, 45),
            backgroundColor: '#FF9E80'
          }, {
            label: 'Replace Desktops on the 3rd Floor',
            dateStart: new Date(year, month, date + 15, 9, 30),
            dateEnd: new Date(year, month, date + 15, 10, 45),
            backgroundColor: '#00C853'
          }, {
            label: 'Update Database with New Leads',
            dateStart: new Date(year, month, date + 15, 12, 0),
            dateEnd: new Date(year, month, date + 15, 14, 15),
            backgroundColor: '#FF6D00'
          }, {
            label: 'Mail New Leads for Follow Up',
            dateStart: new Date(year, month, date + 15, 14, 45),
            dateEnd: new Date(year, month, date + 15, 15, 30),
            backgroundColor: '#9E9E9E'
          }, {
            label: 'Send Territory Sales Breakdown',
            dateStart: new Date(year, month, date + 15, 18, 0),
            dateEnd: new Date(year, month, date + 15, 20, 0),
            backgroundColor: '#26C6DA'
          }, {
            label: 'Territory Sales Breakdown Report',
            dateStart: new Date(year, month, date + 16, 8, 45),
            dateEnd: new Date(year, month, date + 16, 9, 45),
            backgroundColor: '#C5CAE9'
          }, {
            label: 'Report on the State of Engineering Dept',
            dateStart: new Date(year, month, date + 16, 14, 45),
            dateEnd: new Date(year, month, date + 16, 15, 30),
            backgroundColor: '#689F38'
          }, {
            label: 'Staff Productivity Report',
            dateStart: new Date(year, month, date + 16, 16, 15),
            dateEnd: new Date(year, month, date + 16, 19, 30),
            backgroundColor: '#D500F9'
          }
        ]
    
      }
    }
  6. The next step is to provide this service in our application, so open the main.ts file and add pass options to the bootstrapApplication method:
    bootstrapApplication(AppComponent, {
      providers: [
          DataService
      ]
    });

This is the way of using dependency injection with standalone components.

Filling Smart.Scheduler with data

Now since we have an injectable service, it is time to inject it in our AppComponent and use the GetData method to fill the Smart.Scheduler

Open app.component.ts and add the following constructor that will inject our service:

constructor(private dataService: DataService) {}

Now use the GetData function to pass records to the scheduler

dataSource = this.dataService.GetData();

Result

Our Smart.Scheduler is ready and filled with data, this should be the result of the help topic: