A preview of what you will build:
This tutorial has an accompanying GitHub repository called carbon-tutorial-angular that we’ll use as a starting point for each step.
To begin, fork carbon-tutorial-angular using your GitHub account.
Go to your forked repository, copy the SSH or HTTPS URL and in your terminal run the two commands to get the repository in your local file system and enter that directory.
git clone [your fork SSH/HTTPS]cd carbon-tutorial-angular
Add a remote called upstream
so we can eventually submit a pull request once you have completed this tutorial step.
git remote add upstream git@github.com:carbon-design-system/carbon-tutorial-angular.git
Or, if you prefer to use HTTPS instead of SSH with your remotes:
git remote add upstream https://github.com/carbon-design-system/carbon-tutorial-angular.git
Verify that your forked repository remotes are correct:
git remote -v
Your terminal should output something like this:
origin [your forked repo] (fetch)origin [your forked repo] (push)upstream git@github.com:carbon-design-system/carbon-tutorial-angular.git (fetch)upstream git@github.com:carbon-design-system/carbon-tutorial-angular.git (push)
Now that we have our repository set up, let’s check out the branch for this tutorial step’s starting point. Run the two commands:
git fetch upstreamgit checkout -b angular-step-1 upstream/angular-step-1
Add a temporary remote called starter
so we can clone the carbon-angular-starter.
git remote add starter git@github.com:carbon-design-system/carbon-angular-starter.git
Or, if you prefer to use HTTPS instead of SSH with your remotes:
git remote add starter https://github.com/carbon-design-system/carbon-angular-starter.git
Now that we a have starter remote, we can rebase our branch to match whatever is in the starter app. Run the two commands:
git fetch startergit pull --allow-unrelated-histories starter master
Remove the temporary remote called starter
since we have no use for it anymore.
git remote remove starter
We have the repository forked to your GitHub account, cloned down to your machine, and the starting branch checked out. Next, install the Carbon app’s dependencies with:
npm install
After the dependencies are installed, you can start the app with:
npm run start
Your app should now be running with the message: ** Angular Live Development Server is listening on localhost:4200, open your browser on http://localhost:4200/ **
That’s it! Your browser should now resemble the preview above. You can skip create your own and jump straight to submit pull request
Since we are starting from scratch, we need to first install Angular CLI
npm install -g @angular/cli
Now that we have our environment set up, starting a new Angular app is easy! We will be using the Angular CLI to create and generate our components. It can also generate services, router, components, and directives.
To create a new Angular project with Angular CLI, just run:
ng new carbon-angular-tutorial --directory ./
When you get prompted, enter the following.
? Would you like to add Angular routing? Yes? Which stylesheet format would you like to use? SCSS
This command will install the Angular app with all the configurations needed. Currently, the src
directory should have the structure:
src├── app│ ├── app-routing.module.ts│ ├── app.component.html│ ├── app.component.scss│ ├── app.component.spec.ts│ ├── app.component.ts│ └── app.module.ts├── assets├── environments│ ├── environment.prod.ts│ └── environment.ts├── favicon.ico├── index.html├── main.ts├── polyfills.ts├── styles.scss└── test.ts
Even though we installed some dependencies while creating the new app, we’ve yet to install the Carbon packages.
carbon-components
- component stylescarbon-components-angular
- Angular components@carbon/icons-angular
- Angular iconsnpm install carbon-components carbon-components-angular @carbon/icons-angular
In styles/styles.scss
, import the Carbon styles by adding the following to the top of the file:
@import '~carbon-components/scss/globals/scss/styles';
Now we can run our app for a quick preview inside the browser.
npm run start
Your app should now be running with the message: ** Angular Live Development Server is listening on localhost:4200, open your browser on http://localhost:4200/ **
Before we start adding components we want to start with an empty project, so delete everything in app.component.html
except for the router-outler
. We will also have to delete the test that was associated with this code. So in app.component.spec.ts
, delete the should render title
test.
Next, we’re going to create an Angular component called StarterHome
using Angular CLI. We will also need a module and routing files.
ng g module starter-home --routingng g component starter-home/starter-home
You should now have the following folder structure:
src/app/starter-home├── starter-home│ ├── starter-home.component.html│ ├── starter-home.component.scss│ ├── starter-home.component.spec.ts│ └── starter-home.component.ts├── starter-home-routing.module.ts└── starter-home.module.ts
Next, we will edit the code style to match Carbon angular recommendations. Through the conventions listed in our tslint.js
, the app will look clean and easier to read and maintain. So replace your code in tslint.json
with the code below.
{"rulesDirectory": ["node_modules/codelyzer"],"rules": {"callable-types": true,"class-name": true,"comment-format": [true,"check-space"],"curly": true,"eofline": true,"forin": true,"import-blacklist": [true],"import-spacing": true,"indent": [true,"tabs",2],"interface-over-type-literal": true,"label-position": true,"max-line-length": [true,140],"member-access": false,"member-ordering": [true,{"order": ["public-static-field","protected-static-field","private-static-field","public-static-method","protected-static-method","private-static-method","public-instance-field","protected-instance-field","private-instance-field","public-constructor","protected-constructor","private-constructor","public-instance-method","protected-instance-method","private-instance-method"]}],"no-arg": true,"no-bitwise": true,"no-console": [true,"debug","info","time","timeEnd","trace"],"no-construct": true,"no-debugger": true,"no-duplicate-variable": true,"no-empty": false,"no-empty-interface": true,"no-eval": true,"no-inferrable-types": [true, "ignore-params"],"no-shadowed-variable": true,"no-string-literal": false,"no-string-throw": true,"no-switch-case-fall-through": true,"no-trailing-whitespace": true,"no-unused-expression": true,"no-use-before-declare": true,"no-var-keyword": true,"object-literal-sort-keys": false,"one-line": [true,"check-open-brace","check-catch","check-else","check-whitespace"],"prefer-const": true,"quotemark": [true,"double"],"radix": true,"semicolon": [true,"always"],"triple-equals": [true,"allow-null-check","allow-undefined-check"],"typedef-whitespace": [true,{"call-signature": "nospace","index-signature": "nospace","parameter": "nospace","property-declaration": "nospace","variable-declaration": "nospace"}],"typeof-compare": true,"unified-signatures": true,"variable-name": [true,"ban-keywords","check-format","allow-leading-underscore"],"whitespace": [true,"check-branch","check-decl","check-operator","check-module","check-separator","check-rest-spread","check-type","check-preblock"],"directive-selector": [true, "attribute", ["app", "test"], "camelCase"],"component-selector": [true, "element", ["app", "test"], "kebab-case"],"no-inputs-metadata-property": true,"no-outputs-metadata-property": true,"no-host-metadata-property": true,"no-attribute-decorator": true,"no-input-rename": true,"no-output-rename": true,"no-forward-ref": true,"use-lifecycle-interface": true,"use-pipe-transform-interface": true,"templates-use-public": true,"invoke-injectable": true}}
Now that our guidelines are defined, we need to apply them to our app.
ng lint --fix
All files should now pass linting. Finally, to help the editor indent lines properly in our project and to keep code styles consistent, we need to edit .editorconfig
.
# Editor configuration, see https://editorconfig.orgroot = true[*]charset = utf-8indent_style = tabindent_size = 4insert_final_newline = truetrim_trailing_whitespace = true[*.md]max_line_length = offtrim_trailing_whitespace = false
Note: This only works with editors that support editorconfigs
The StarterHome
component will hold the content of the starter app. We will add the grid, list, tabs and tiles Carbon components. Now, let’s import these Carbon components from our carbon-components-angular
package library.
import {GridModule,ListModule,TabsModule,TilesModule,} from 'carbon-components-angular';
imports: [CommonModule,StarterHomeRoutingModule,GridModule,ListModule,TabsModule,TilesModule],declarations: [StarterHomeComponent]
Note: Make sure to add these imports to starter-home.component.spec.ts
to ensure our tests pass.
Next, let’s add some markup and styling to match the starter app.
<div class="starter-home" ibmGrid><h1 class="title">Congratulations, <br />you made it!</h1><p style="margin-top: 2rem;">You have offically built your first Carbon Angular app</p><div class="body-text" ibmRow><div ibmCol [columnNumbers]="{'lg': 6, 'md': 12, 'sm': 12}"><p>This app is to get you quickly started with our Carbon Angularlibraries. It currently includes the grid, list, tab and tilecomponents. Feel free to add or remove any components you desire. Tohelp you get started we've also set up:</p></div><div ibmCol [columnNumbers]="{'lg': 6, 'md': 12, 'sm': 12}"><ul ibmList class="list"><li ibmListItem>Angular-cli</li><li ibmListItem>Build Process</li><li ibmListItem>Code styles <br />& editor configs</li><li ibmListItem>Folder structure</li><li ibmListItem>Lazy loading</li><li ibmListItem>Routing</li><li ibmListItem>Service workers</li><li ibmListItem>Test framework</li></ul></div></div><ibm-tabs isNavigation="false"><ibm-tab heading="carbon-components-angular"><p>Description</p><br /><p style="margin-bottom: 2rem;">A component library that gives developers a collection of re-usableangular components that they can use for building websites and userinterfaces</p><p>Other useful resources</p><br /><div ibmRow><div ibmCol [columnNumbers]="{'md': 2, 'sm': 12}"><ibm-clickable-tilehref="https://github.com/IBM/carbon-components-angular"target="_blank">Repository</ibm-clickable-tile></div><div ibmCol [columnNumbers]="{'md': 2, 'sm': 12}"><ibm-clickable-tilehref="https://angular.carbondesignsystem.com/"target="_blank">Component Library</ibm-clickable-tile></div><div ibmCol [columnNumbers]="{'md': 2, 'sm': 12}"><ibm-clickable-tilehref="https://angular.carbondesignsystem.com/documentation/"target="_blank">Documentation</ibm-clickable-tile></div><div ibmCol [columnNumbers]="{'md': 2, 'sm': 12}"><ibm-clickable-tilehref="https://www.npmjs.com/package/carbon-components-angular"target="_blank">NPM</ibm-clickable-tile></div></div></ibm-tab><ibm-tab heading="carbon-charts"><p>Description</p><br /><p style="margin-bottom: 2rem;">Carbon Charts is an open-source JavaScript data visualization librarythat will be used as a functional component of IBM's Carbon DesignSystem.</p><p>Other useful resources</p><br /><div ibmRow><div ibmCol [columnNumbers]="{'md': 2, 'sm': 12}"><ibm-clickable-tilehref="https://github.com/IBM/carbon-charts"target="_blank">Repository</ibm-clickable-tile></div><div ibmCol [columnNumbers]="{'md': 2, 'sm': 12}"><ibm-clickable-tilehref="https://carbon-design-system.github.io/carbon-charts/"target="_blank">Demo</ibm-clickable-tile></div><div ibmCol [columnNumbers]="{'md': 2, 'sm': 12}"><ibm-clickable-tilehref="https://carbon-design-system.github.io/carbon-charts/documentation/"target="_blank">Documentation</ibm-clickable-tile></div><div ibmCol [columnNumbers]="{'md': 2, 'sm': 12}"><ibm-clickable-tilehref="https://www.npmjs.com/package/@carbon/charts"target="_blank">NPM</ibm-clickable-tile></div></div></ibm-tab></ibm-tabs></div>
.starter-home {.title {font-size: 4rem;font-weight: 400;}.body-text {margin-top: 2rem;margin-bottom: 4rem;}.list {max-width: 500px;padding-left: 50px;column-count: 2;@media only screen and (max-width: 1055px) {margin-top: 3rem;}li {font-weight: bold;}}}
We will also add some styling in src/styles.scss
for resets, font styles and the different themes that you can play around with.
$feature-flags: (css--body: false,// we're providing our own body stylescss--reset: false // prevent thousands of resets being included...,,);body {// To change the theme, uncomment the below import and whichever carbon theme you want to use// @import "~carbon-components/scss/globals/scss/vendor/@carbon/elements/scss/themes/theme-maps";// $carbon--theme: $carbon--theme--g100;// $carbon--theme: $carbon--theme--g90;// $carbon--theme: $carbon--theme--g10;@import '~carbon-components/scss/globals/scss/styles';color: $text-01;background-color: $ui-background;@import '~carbon-components/scss/globals/scss/css--reset';@include reset;position: absolute;top: 0;left: 0;margin: 0;min-width: 100vw;min-height: 100vh;font-family: 'IBM Plex Sans', Arial, sans-serif;p {@include type-style('expressive-paragraph-01');max-width: 800px;}li {@include type-style('body-long-02');}}
Currently, we you will not be able to see anything in the browser since our routing is not set up yet. Angular CLI has already set up routing in app-routing.module.ts
and starter-home-routing.module.ts
, we just need to add the routes:
const routes: Routes = [{path: '',loadChildren: () =>import('./starter-home/starter-home.module').then(m => m.StarterHomeModule),},{path: '',redirectTo: '',pathMatch: 'full',},];
import { StarterHomeComponent } from './starter-home/starter-home.component';const routes: Routes = [{path: '',component: StarterHomeComponent,},];
Before we submit a pull request, let’s explore progressive web app, or PWA. PWA is a web application that has a set of capabilities (similar to native apps) which provide an app-like experience to users. Some other capabilities include full responsiveness and browser compatibility, connectivity independence and self-updates. In the src
directory create a file called sw.js
and paste the code below.
For more information on PWAs, check out the developer’s documentation.
let log = console.log.bind(console);let err = console.error.bind(console);let version = '1';let cacheName = 'pwa-client-v' + version;let dataCacheName = 'pwa-client-data-v' + version;let appShellFilesToCache = ['./','./index.html',// "./inline.bundle.js",// "./polyfills.bundle.js",// "./styles.bundle.js",// "./vendor.bundle.js",// "./main.bundle.js",'./manifest.json',];self.addEventListener('install', ev => {ev.waitUntil(self.skipWaiting());log('Service Worker: Installed');ev.waitUntil(caches.open(cacheName).then(cache => {log('Service Worker: Caching App Shell');return cache.addAll(appShellFilesToCache);}));});self.addEventListener('activate', ev => {ev.waitUntil(self.clients.claim());log('Service Worker: Active');ev.waitUntil(caches.keys().then(keyList => {return Promise.all(keyList.map(key => {if (key !== cacheName) {log('Service Worker: Removing old cache', key);return caches.delete(key);}}));}));});self.addEventListener('fetch', e => {log('Service Worker: Fetch URL ', e.request.url);// Match requests for data and handle them separatelye.respondWith(caches.match(e.request.clone()).then(response => {return (response ||fetch(e.request.clone()).then(r2 => {return caches.open(dataCacheName).then(cache => {console.log('Service Worker: Fetched & Cached URL ', e.request.url);cache.put(e.request.url, r2.clone());return r2.clone();});}));}));});
Now we need to register our service worker and use it to cache files locally. In index.html
add the below code in a script block using <script></script>
under the app-root
tag.
// Uncomment the following lines to activate the service worker // if(navigator.serviceWorker) { // navigator.serviceWorker.register("sw.js").then(()=> { // console.log("Service worker installed") // }, err => { //console.error("Service worker error:", err); // }); // }
Next, we need to add the web app manifest. The manifest is a file in json
format that provides the name, description, icon locations and other information required for an app to be considered a PWA. It lets users install the web app on the home screen just like native apps without going through an app store. Create a manifest.json
in the src
directory the paste the following code.
{"name": "Carbon Angular Starter","short_name": "Starter","icons": [{"src": "/assets/icons/favicon-32x32.png","sizes": "32x32","type": "image/png"},{"src": "/assets/icons/android-chrome-192x192.png","sizes": "192x192","type": "image/png"},{"src": "/assets/icons/icon-144x144.png","sizes": "192x192","type": "image/png"},{"src": "/assets/icons/icon-192x192.png","sizes": "192x192","type": "image/png"},{"src": "/assets/icons/icon-256x256.png","sizes": "256x256","type": "image/png"},{"src": "/assets/icons/icon-384x384.png","sizes": "384x384","type": "image/png"},{"src": "/assets/icons/icon-512x512.png","sizes": "512x512","type": "image/png"}],"background_color": "#ff00ff","theme_color": "#ffff00","display": "standalone","start_url": "/"}
We will also need to add sw.js
and manifest.json
into our asset entities (build & test) in angular.json
and reference the manifest.json
and theme-color
in the index.html
<head>
tags. The theme color tells the browser with what color to tint UI elements such as the address bar.
"assets": ["src/favicon.ico","src/assets","src/sw.js","src/manifest.json"],
<link rel="manifest" href="manifest.json" /><meta name="theme-color" content="#ffff00" />
Finally, let’s download the different sizes of icons to the src/assests/icons
directory by running the following commands:
mkdir src/assets/iconscurl -o src/assets/icons/android-chrome-192x192.png https://raw.githubusercontent.com/carbon-design-system/carbon-angular-starter/master/src/assets/icons/android-chrome-192x192.pngcurl -o src/assets/icons/icon-144x144.png https://raw.githubusercontent.com/carbon-design-system/carbon-angular-starter/master/src/assets/icons/icon-144x144.pngcurl -o src/assets/icons/icon-192x192.png https://raw.githubusercontent.com/carbon-design-system/carbon-angular-starter/master/src/assets/icons/icon-192x192.pngcurl -o src/assets/icons/icon-256x256.png https://raw.githubusercontent.com/carbon-design-system/carbon-angular-starter/master/src/assets/icons/icon-256x256.pngcurl -o src/assets/icons/icon-384x384.png https://raw.githubusercontent.com/carbon-design-system/carbon-angular-starter/master/src/assets/icons/icon-384x384.pngcurl -o src/assets/icons/icon-512x512.png https://raw.githubusercontent.com/carbon-design-system/carbon-angular-starter/master/src/assets/icons/icon-512x512.png
We’re going to submit a pull request to verify completion of this tutorial step and demonstrate a couple related concepts.
Note: Before you run any tests, make sure that you are using ChromeHeadless in karma.conf.js
instead of Chrome.
We have lint
and test
scripts defined in package.json
that verify file formatting for files that have been touched since the last Git commit. You’d typically also have that script run your test suite as part of your CI build. Go ahead and make sure everything looks good with:
npm run lint && npm test
Note: If this gives an error, it’s likely that some of your source files are not properly formatted.
Before we can create a pull request, we need to stage and commit all of our changes:
git add --all && git commit -m "feat(tutorial): complete step 1"
Then, push to your repository:
git push origin angular-step-1
Note: If your Git remote protocol is HTTPS instead of SSH, you may be prompted to authenticate with GitHub when you push changes. If your GitHub account has two-factor authentication enabled, we recommend that you follow these instructions to create a personal access token for the command line. That lets you use your token instead of password when performing Git operations over HTTPS.
Note: If you receive a non-fast-forward
error, it’s likely that your forked repository is behind the original repository and needs updated. This can happen if the tutorial was updated after you began working on it. To fix, run git pull upstream angular-step-1
to merge the changes into your branch, then you can try pushing again. Or, you can manually merge in the upstream changes.
Finally, visit carbon-tutorial-angular to “Compare & pull request”. In doing so, make sure that you are comparing to angular-step-1
into base: angular-step-1
. Take notice of the Netlify bot that deploys a preview of your PR every time that you push new commits. These previews can be shared and viewed by anybody to assist the PR review process.
Note: Expect your tutorial step PRs to be reviewed by the Carbon team but not merged. We’ll close your PR so we can keep the repository’s remote branches pristine and ready for the next person!