What do you want to learn?
Skip to main content
Building a Web Application with Polymer.js and Material Design
by Bill Stavroulakis
This course will introduce Polymer’s basic functionality by building together a real-life administration dashboard.
Resume CourseBookmarkAdd to Channel
Table of contents
Hi, this is Bill Stavroulakis and welcome to this course on Building a Web Application with Polymer.js and Material Design. We are hired. Let's imagine that an educational institution hired us to create a dashboard for their school. They want a simple authentication where they can log in, preview some data for their school, change the profile information, and view/edit their staff information. A simple chat is also necessary for them to chat with each other. They would like a fully responsive, single page, real time web application that can be extensible with any backend technology such as Node.js, C#, PHP, or Ruby, as they haven't decided yet. Time for us to create a simple, strong, extensible, and easy editable mockup to convince them that we are on the right track. We can select the wide range of front-end technologies such AngularJS, EmberJS, Backbone.JS and UI libraries such as Bootstrap.js, however, we will select Polymer.js and Material Design for the job and see where it will take us. By creating this application together, you will understand in action the fundamentals of web components, material design and the Polymer.js framework.
Let us view the end result of our application. At the end of this course you'll fully understand how to create this application with the use of Polymer.js. First of all, let's preview the login page. As you reenter the username and the password and click on enter, we have successfully logged in the home page. In the home page you can preview some blocks of data and a welcome message. On the left there is a menu with our pages and on the right there is a drawer with our friends. We can either pin or unpin our drawers or open and close them. We can click on the profile link and preview or edit our profile. Also there is a staff page where we can search, add, edit, and delete staff members in our application. If we click on a user on the right, we can chat with them. Let me open two tabs so you can see that this is real time as well. So once we send a message on one page, it automatically updates on the other. Finally you can also notice that our application is fully responsive as well. As we decrease the width of our application, you can observer that the drawers unpin automatically to create some space and sorting our blocks accordingly. So it is time to dive in and create this application together with Polymer.
Who This Course Is For
Working Example - Structure
Hi. This is Bill Stavroulakis and welcome to the second module of this course on building a web application with Polymer.js and Material Design. In this module we'll create the basic shell of our application. We'll begin setting up our environment and we'll create a simple drawer system. While implementing these sections, we'll go over together the basics of Polymer.js.
Okay, I know that the hardest part of an application is the beginning. There are so many parts that you have to juggle at the same time. That is why usually we use starter kits or Bootstrap packages that give us a nice wrapper and starting point to work with. For Polymer, you can check out the Polymer Starter Kit which offers a nice base to begin with; however, I would like us to create this application from the beginning so we can set up each layer together, learning concepts and strategies at the same time. You can preview a big part of the project at the link below as it is a part of the Polymer Dashboard project. It is open source and on GitHub so don't hesitate to fork it and contribute any changes or fixes.
A good starting point would be to create a shell or skeleton of our application. Let us see what sort of technologies we'll need to set up our basic application. I'm using Windows 10 and we'll work on Visual Studio Code as my text editor. You can use any HTML/CSS/JS editor you like such as WebStorm or Sublime. For rapid prototyping I'll be using NodeJS as a very simple backend for our application since we will focus mostly on the front end side. To run NodeJS and other technologies that we'll use such as _____, you have to download NodeJS from Node.js.org and the Git Bash for Windows so you can run the commands necessary from msysgit.github.io. Everything seems ready. Let us create a folder where we'll add all of the files of our application. We'll open Git Bash and navigate to that folder. To keep my paths nice and short, I'll use the d drive and create a folder with the name polymer-project. Now it's time to set up our project.
The Application Shell
Time to open Visual Studio Code so we can write some code. After installing Visual Studio Code you can double click on the shortcut on your desktop to open the application. Then we'll click on file, open folder, and find the folder we created in the previous video to load our project. We'll create two folders; the app folder which will include our application and the demo server folder which will include our NodeJS code. Also, let us create a package.json file for our node model settings. The first file we'll create in our app is index.html which will run as our default page. We'll add some boilerplate HTML code and the text test in the body tag. In our package.json file we'll add the following settings which will declare the Node modules needed for our application. For now we will need the Express module to run our web application. In our app.js file we include the Express module, initialize it, and include the path module. For our default path we'll serve the index.html file and set up the http module to listen to the 8080 port. From the Git Bash command line we will open the demo server folder, run npm install to install the Node dependencies, and run node app js to listen to our port and serve the index.html file. Let us run local host 8080, now on our browser so we can see the test text and our boilerplate html.
Our First Element
Anatomy of an Element - Properties
Anatomy of an Element - Computed Properties
In the pd-drawer element declaration I've added numerous new properties that we will be using throughout our application. Sometimes in our code we need a bit more complicated properties that are a combination of others. In this element we'll need a property that will return the main classes or our element concerning various states. This class is named mainClasses property and we can see it as a string and it is in the computed property. We'll add the method we want to return the value of the mainClasses property. Also, the values that are entered in the method are important because once one of those changes then Polymer will rerun the method and refresh the value of the property. I'll create the method to return the classes and add the property as a class attribute in the drawer elements. So now, once we refresh the page, we can preview the classes, depending on the various states our drawer is in.
Anatomy of an Element - Tap Events
Anatomy of an Element - Insertion Points
In this video we'll go over the very interesting concept of insertion points. As mentioned, components are created so we can reuse them. How can I make the pd-drawer not contain any of my application logic but still use it and reuse it when needed? By now, the way we have created the pd-drawer element, we can reuse it in any of our applications. We just have a chunk of HTML that is the header, a main section, and two drawers. In each of our applications, the content in the header, drawer, and main section will be different. Going back to our pd-dashboard, I'll add some HTML in the pd-drawer. This is our application level code that we want to insert in the pd-drawer element, so we'll have the logo, left menu, right menu, and main section HTML. After returning to our pd-drawer element, I'll add the insertion points with the special content tag. Each content tag has a select attribute that works as a selector to translate our selector. This says, if in the element, when declared you find another element with a class logo, render it over here; the same for the left drawer and the right drawer. We'll refresh our page and see our drawer and the HTML specified in the pd-dashboard inserted in a way in the sections specified.
If you're still here, then I salute you. This probably is the end of the hardest module of this course, since it was the first touch with numerous new concepts and ways of thinking. We basically created the main structure of our site while introducing the basic concepts of Polymer.js. In the next module we'll try to style what we just created and learn about theming, coloring, and material design.
Working Example - Styling
In this module we'll talk about CSS and our elements. We'll also dress our site by creating a theme, colors, and seeing what is Material Design and how can we use its principles in our dashboard?
Anatomy of an Element - CSS
Our pd-drawer works fine, but life is not pretty without CSS. We'll open pd-drawer.css and add some CSS in our file and save. In the pd-drawer.html you can see the dom-module element that contains the html of our elements. In it we can include a link tag with a CSS reference. The CSS included in the dom-module will have as scope only the html in the elements and won't be global. So any CSS styles we include will style the html in this section only. How can this be done? If we preview the end results, you can notice that Polymer is adding the style element of that element in the head and if we expand that, you can see that it has wrapped each declaration with that element's name. If we added the link before the dom-module element, the scope would be global.
A web page without color is like a programmer without coffee. Well, not exactly, but you get my point. We need color rules. My first step will be to create a folder named skins in the CSS folder and add one skin for now name default. I'll also create two template files called color-vars-templates.scss and skin-template.scss. These two files will contain CSS rules with values, different variables. Now in the default folder we'll add a vars.scss file for our color variables. Let me add some values in there. In my template.scss files, I'll add my color variables. In the template files we'll include the CSS rules as mentioned previously. We'll include these template files in our skins to load them with the variables and colors of the skin, but the rules will be the same. You can check out this CSS code in the demo files, and in each skin we'll create our files, that first include the variables of that skin and then the generic template. We'll open package.json and add some new Node modules. Then in gulpfile.js we will initialize the modules, add a new Sass task to compile the skins as well, create a copy task to copy the colorVars body.css file to the colorVars.css file. Create an insert task to append the style tag in the colorVars.css file. And add a default task that will run a sequence of tasks. It will first run the Sass, then the copy task, and finally the insert task. Now if we run npm install on Git Bash to install the modules and run Gulp on Git Bash, it will run the sequence of tasks located in the default task. In the CSS file created, you can see the CSS rules with the corresponding variables. In the color.css file we have our standard CSS rules that color our elements and classes. Lastly, in colorVars.css you can preview the tag that was appended through the Gulp insert task. Time to include our skins in our application. I'll include these CSS files with Polymer's special link tag. By now, you should be okay with the colors.css class; however, you may be a bit curious on what the colorVars.css file is all about, and why did we include it in the page with the rel import attribute and not with the rel style sheet attribute? If you visit the link below, you'll notice a very cool new CSS 3 feature which are CSS's variables. Polymer implements this technology seamlessly in its framework. Let us review an example. I'll open Git Bash and run node demo-server/app.js to load my site. After refreshing the site, we can see the colors loading properly. Returning to pd-drawer, let us create a new div in our main section with the class main site. Then we'll add the background color for that section and as a background color, we'll use the primary-color- dark variable declared in the colorVars.css file. After refreshing the page we can see that the section defined has the primary dark color. So as you're defining a variable, importing it with the rel import tag, we can use those variables in our elements. Polymer uses certain variables in all of its elements. This would be a good time to include in bower.json all of the elements that we'll be using in our project and run bower install to install them. For example, if we open the paper-icon-button element, you can see that it is applying the primary-text-color variable. If we visit materialpalette.com and select two colors, click on downloads and Polymer, you can see a collection of variables depending on the colors we selected. If we were to import these parameters in our pd-dashboard element, then any element in the pd-dashboard would implement the color palette selected with the variable specified.
This would be a good time to talk about the scope of CSS in our elements. In our pd-drawer I'll add some custom CSS and I'll split the screen into sections. On one side you can see our html as it is in our code and on the other side you can see how our html has rendered. So the host selector will have us scope the pd-drawer element. The root selector will have the parent of the pd-drawer. The content selector is used to scope the content tag. The shadow selector is used to select the content inside of another element, but only one level deep and lastly, the deep selector is used to scope all of the elements inside of the element selected.
In this module we talked about styling in our application. We saw how CSS is used inside our elements and created the simple theme and coloring system. Lastly, we talked about Material Design and how it will be used in our application.
In this module we'll set up the routing structure of our dashboard. There should be a way where different links will load different pages dynamically, as this is a single page application. In this module we'll set up a small system to do exactly that.
Time to make our application more alive by dynamically loading different pages depending on our routes. I'll create another element as always to solve my problem. Let us name this one pd-flatiron-director as it will extend the flatiron-director library which you can download over here. I'll include this third-party library in my project. Included as a global scope in our application and add the boilerplate code for my new element. Then we'll add a route parameter and a router getter. The getter, once called, will return the global private_router object and if it is not set, will instantiate the flatiron router. Then in our ready callback function, we can add an event that will trigger once the router is changed and set that value to our local property. Also, on our first load, I'll set the route property and if it is empty it is can redirect to an empty page. It is time to add our external pages. Let us create a folder named pages and add the home, the profile, and the staff pages. In each page, I'll add some dummy text for now. I will return to the pd-dashboard element now and create a local route property. We can include the pd-flatiron element and add it in our pd-dashboard element. Now we'll bind the local route attribute with pd-flatiron-directors route attribute. So once the attribute changes, the updates will apply to our local route property and the observer will trigger. Observers are special methods that are triggered once our properties have changed, sending as parameters the old and the new value. In the next video we see how we can load each page dynamically.
In bower.json we'll include the iron-ajax element and run bower install to include that element in our bower components folder. I'll include this element and add it in pd-dashboard as well. The iron-ajax element is very interesting as it works as an element that exposes network request functionality. If we visit the polymer-project.org and click on catalog, you can view here the complete list of Polymer's custom element library. The iron library contains the most basic elements. You can find the iron-ajax element over here and preview the documentation. Returning to our application now, we'll implement the iron-ajax element, and once the route has changed, we'll change the url with the page specified and run the generateRequest method to trigger a request. Then in the ready callback we'll add an event listener to handle the response. So once we receive back the page specified, we'll include the page's content to our main area. The self.$ is a selector that takes us in the template element and then we can select the template with its id. We have a div with the id main. The way to select that is with self that selects the element, the $ sign which is the template tag, and main which is the id of the div. Then we'll reset the content and append the new body content received from the request. For the header content, we'll select all of the links and loop through them. If our document doesn't have that resource already loaded, we'll add that resource to the head of our document. After we refresh the page and click on each link, you can see that we have our basic routing ready. Also, if you load a page, for example profile, that page is automatically selected and from there on the user would dynamically load data from each page depending on the route.
The last couple of chapters close an interesting chapter in our application. We went over so many basic principles of Polymer such as declaring, including, and implementing elements. The properties of our elements, computed properties, insertion points, CSS in our elements, and events. We also finished our basic application shell with routing as well. In the next module we'll go over authentication and create a simple login system.
Hi. This is Bill Stavroulakis and welcome to the fifth module of this course on authentication in our web application. In this module we'll create a simple REST service, secure our application, and create a simple login system.
Simple Backend JSON Server
In the previous modules we made some huge steps together. Through the implementation of our basic app structure you now know a substantial part of Polymer's basics. In this module we'll work with our site's REST service and authentication. Time to create a simple REST service so we can interact with our site's backend. I'll install a Node module called json-server. Let us add the library in our package-json file and run npm install to install the package. Then we'll go back to the app.js file and include and instantiate the json-server object. Then we'll make this service to listen to port 5000 and create a db.json file to add a big JSON object. The JSON file will work as a database representation so we can persist and collect data from. Let me run node demo-server/app.js again to run our services and visit local host 5000. The json-server package has read the db-json file and created a quick REST service for use where we can make get requests and receive part of our big JSON file. For example, if I run localhost5000/users you get a list of the site's users. Then if I run localhost/users/1 we'll get the user that has the id of 1 or we can make a more complicated request like localhost/users?username=bill, so we can get the user with the username Bill. We can also make post requests to persist data. For example, I have this post request ready. To change the username of one of my users from Chris to Joy. After running the post request let me run localhost5000/users and you can see the username changed. Perfect. Now we have our site running on port 8080 and our REST service running on port 5000. Time to add some security and authentication.
Simple Backend Security
I'll add two new packages in our package.json file named cookie-parser and express-session. Then I'll run npm install to install these two new packages. After that I'll visit the app.js file and load my two new packages. We want security on the JSON service and on our app as well, so I'll inform both packages to use the cookie- parser. Instead of security you have to add your own string with high entropy as the cookie-parser will encrypt and decrypt the cookie data received from the user, depending on that string. Also, in our json-server object I'll add my own use function, to check whether or not the user requesting the data has a signed cookie. If not, we'll redirect him to the authentication page. If he does, we'll allow for the next step to continue. We'll do a similar method to our basic application by filtering the request and forwarding the user depending whether he has a valid cookie or not. When the user tries to load the authentication page though, we'll have to bypass the security feature and serve him the authentication page whether he has a cookie or not, since he'll have to access it with no security. Finally, I'll create an empty authentication page for now, just to test if the authentication process is working. Let us run node demo-server/app.js again to run our two services and try to enter the localhost8080 page. You can see that we are redirected to the authentication page. The same occurs with our localhost5000 page as well.
In the previous video we saw how we can secure our pages but also serve the authentication page when the user doesn't have a valid cookie in his requests. In this video we'll work on our authentication page to offer the ability to the user to log in into our site. First, in the auth.html page I'll add some standard boilerplate html. This is our standard html code boilerplate with our head section and our body section. The only difference is that we'll include the components lite library to enable the rel import tag and include with the rel import our auth dialog component. Lastly, we'll include the component in our body section as well. Then I'll create a new Sass file named auth.scss and add some custom CSS. This SCSS will be used to style our auth-dialog. You can find this file in the demo files or you can post the video and copy the code. This SCSS file will also compile to a CSS file. For more info on this you can preview the styling module of this course. Then, I'll open gulp file and add the new task to compile this SCSS file. After running gulp sass to compile the Sass code I'll create another file named auth-dialog.html to create a new element in that file. Again, I'll include some standard boilerplate code used for my elements. Then we'll add our theme CSS, the auth.css and include some other elements as well. These elements included our elements created from the Polymer team. You can visit the following site, elements.polymer-project.org for the full list of elements and include them and reuse them in your projects as well. We will be using numerous paper elements that comply with the Material Design principles out of the box. To download the files necessary for this to work in our project we'll have to include them in our bower-json file and run bower install in our console. If we open bower_components we can view these libraries loaded, so we're ready to go. Time to add some html in our element for our login form. This section is pretty straightforward. We have two input tags, one for our username and one for our password. A remember-me checkbox and lastly a login button. These elements, the paper input, paper checkbox, and paper button are included in our page from the import tags and are installed with the bower-json script and command seen in the previous part of the video. If we reload the page you can see a clear material design card in the center of our page, with the paper inputs, the paper checkbox, and the paper button. Also, we'll add a user property with two-way data binding enabled. When you bind an object element, you can bind specific properties of that object. As seen here, we'll bind the username with the value of the input element and the password with the other input element. In the ready callback of our element, we'll focus the cursor to the username input tag located in the username paper input tag. It looks like we have everything set up. Time to add our login logic in the next video.
I'll open the app.js file and add two code snippets. The first one is for the login post request. We'll collect the username and the password from the parameters of the request. Then we'll go through our users in the db.json file and see if there is a user with those credentials. If the user exists, we'll create a cookie for that user and return it in our response. Also we'll send a JSON response that the request was successful. If the user isn't found, we'll send an error response. The next code snippets are some headers added in every response of our json-server service so we can enable CORS in our service. CORS stands for cross origin resource sharing and that is needed since we'll send requests from our site which is on localhost8080 to our REST service which is running on localhost5000. I'll also add a logout handler, so when the user visits the path/auth/logout, we will clear the cookie and redirect him to the authentication page. Returning to our application, I'll add the iron-agents element so we can make the post request specified to make a login request. I'll also include the paper toast element which will be responsible to display toast messages to our users. Then on our login button click, the login method is called. Let us create that method and make the request from that method. We'll set the username and password parameters in our request from the user object and then run the generate- request method located in our iron-ajax element. Once the request has a response, the on-response callback is triggered, which is our login callback method. This method will receive a response parameter as well. From the response parameter we'll locate the JSON sent from the server, then we'll add an if statement. If the login is successful, we'll redirect to the homepage; if not, we'll show the error message sent from the server as well. Let us refresh our page and try an example. As a username I'll add bill and as a password polymer2. Once I click on login and since these credentials aren't the correct credentials we'll receive an error message. If instead of polymer2 I add polymer, we'll get redirected to the main page. We also have the user session cookie sent which you can preview now in our local cookie collection, and now we are successfully authenticated in our application. Lastly, if we click on the logout button, we can see that we have successfully logged out of our application and have been redirected to the authentication page.
In this module we made our application more dynamic by adding a simple REST service and we connected our application with that service by creating a simple authentication system. We also secured our application from unauthorized users. In the next module we'll progress our application further by reading and updating our profile data through our profile page.
In this module we'll implement the profile page. In the profile page we'll first the user's data and offer the authenticated user the ability to update the ability to update this data. We'll also create a new dropdown element.
The Card Element - Template If
A very popular UI item in Material Design are the card elements. If you visit the following link you can learn more about the card element and how it is used. We'll create our own card element so we can reuse it throughout our application. As usual, I'll create a folder and the html file to host my element. Then I'll copy and paste the code I've written for this element. By now you should be very comfortable with the Polymer element structure. I have the style tag located over the template tag to style my element. Then we have the template tag to store the reusable code used each time we use the pd-card element and after the dom-module declaration, I have my script with some simple logic to set the fin classes if the fill attribute class is set. A new feature we'll introduce are the conditional templates. In our code, we'll want to show or hide html, depending on the status of various properties. In our pd-card element, we'll want to show or hide the header depending on the head attribute. By adding a conditional template, if the head of our element is set, this block will appear. If the head element is not set, this block won't appear. To view the full code of the element you can check out the demo files of this module or the polymer-dashboard.com project. In the next video we'll begin to work on our profile page.
Reading the Data
In this video we'll begin to work on the profile page. We'll include an element named profile-edit and add that element in our page. Now we'll create a new file named profile-edit.html to declare that element. In the profile-edit.html page I'll include the element boilerplate, then I'll use the pd-card element we created in the previous video. In the pd-card element, I'll add as content the form that I want to create. Also, let me add a head with a string profile details. If we revisit the pd-card element, you can see that the content that I added will be rendered in this section and the head will be written in this section. Last, I'll add a paper-toast element to show notifications, and the standard Polymer script. In the properties section I'll add a profile object and as a value of my input tag I'll bind the properties of that object with certain values. We'll also have to include all the other elements that we'll be using in our profile-edit element. Now when everything is ready, I would like to get the data of my user and show them in the form. Let us open the app.js and create a path where the user can get his profile data. We will get the user id from the site's cookie. Then we'll loop through our users until we find that user and return his data as a JSON string. Let us see what we have done until now. I'll restart my server and first of all, visit the site localhost8080. Then I'll click on the profile page and viola! I can preview my form with a nice save button. Then I'll visit localhost5000/profile and I can view the data of my profile as a JSON string. Time to combine these two and preload our data in our page. In the profile-edit element I'll add the iron-ajax element again, which will trigger our get request and have the getProfileCallback method callback. I'll include that callback and set the profile object to the JSON profile returned. And of course, I'll trigger the getProfile once the element is ready. After I reload my page, you can see that my profile data is preloaded on the profile page.
Dropdown Element - Template Repeat
In my profile data, I have two properties that I haven't included in my form yet and that is the status which is active or inactive and the type which is either principle itadmin or teacher. I would like to create a nice dropdown for these properties. We could use our standard HTML5 select tag, but I want to create a more cool reusable select tag. That will be more Material Design-like and we can use throughout our application. I'll visit my components folder and create a new folder for my new select element named pd-select. In the pd-select folder I'll create a pd-select.css and a pd-select.html file. In the pd-select.css we'll add some CSS for our element which you can find in full in the demo files of the module and in the pd-select.html the element boilerplate code to declare our element. I'll include the pd-select.css in my element and the style tag with CSS variables, which we declared in the styling module. Then we'll add our selection wrapper and in the scripts section we'll create a new array property with the notify property set to true and the reflectToAttribute property set to true. Previously we saw the template if tag together that depending on the status of the value, it would either show or hide the html snippet in that tag. Now we're using a template repeat tag. This template repeat tag will loop through the options array and for each item, it will display that item on our page. To see what we've done until now, I'll include the pd-select element in our profile page and add a pd-select element with the options of active and inactive. If we refresh, you can see the two options appearing on the sides. This is done because the template repeat tag looped through the options and for each one, it added a new div tag. Also, the second select tag appears on our page as well; however, it is hidden behind the active and inactive select tag. We'll fix this in the next video.
Dropdown Element - A Cooler Select Element
Let us break down HTML5 select tag. At the beginning, the select tag shows us a friendly select reminder if we haven't selected anything. Once we click on it, we see the toggled open state with the options displaying and once we click on an option, we see the toggled close state with the options hidden and the value selected to appear as a selection. At this point, I'll add some more attributes in my element to mimic this functionality. Let me start with a label and the value properties. Also, a computed property named SelectedEmpty which will return true or false if the value is null or not. I'll select the toggled property so we can set the toggle status to closed or open. And a toggled class computed property that will return the correct class depending the state, and either show or hide our options. Over the options section I'll add this code snippet. (typing) This will display the label property set in our script section. In Polymer there is a special attribute named hidden$. With this, if the property is set to true it will hide the element. So we want to hide our label if the element isn't set. If we haven't selected the value yet, we want to show a friendly message as well and if the selected value isn't empty, we'll display that value. Lastly, I'll add a data-select$ attribute in the div of my options loop tag. The data-something? attribute is used so you can save data in your html, so you can recollect it when needed. So once the user clicks on an option, the select element function is triggered. In this function we'll collect the target of our div clicked and get the data-select attribute. Also, we'll set this toggled state to close, to close the options section. Lastly, we'll add the toggle function so we can interchange the toggle value to either hide or show the options. This toggled function is triggered from this on-click event. Time to revisit the profile element. In the pd-select element now, I'll add the label attribute and bind the value attribute to the profile type property and the profile.status property. If I refresh the page now, we can see that the values are preselected. The label appearing as well, and once I click on the select, I can view my options and change them. Things are going great. Next, we'll continue with the save button and make it save any changes we apply to our profile.
Updating the Data
The profile page is almost ready. We'll only have to make this save button work so we can persist any changes we make on our own form to the backend database. I'll add a new iron-ajax element with the settings needed for us to save our profile data. The url where we'll post the changes is the localhost5000/profiles. It is a post request. The with credentials will send the cookie in our head so the server will know who the authenticated user is and a response callback that will trigger once the request is done. Then when the user clicks or taps on the save button, we have an event set to trigger the saveProfile method. I'll create the saveProfile method to handle this event. We'll attach in the body of our request the profile data and set the content type of our request to application JSON. Then we'll trigger the request. Also, I'll add the saveProfileCallback method which will trigger after the request is done where we'll show a success message to the user. I'll refresh the page and open the Google debugger. Then I'll change the name from Bill to Billy and click save. We can see the success message. In our network tab, you can see the post request made. The request header has various standard settings set and the encrypted cookie with the authenticated user's information. In the body of the request, you can see the JSON object sent and as a response header, we can see the various attributes set for cross-browser requests and other standard information. Once I refresh the page again we can see the name set to Billy. Also, if we call our REST service, we can see from there again that the data has persisted on the back end.
In this module, we finished the profile page by previewing and updating the user's data. We also created two new cool reusable elements, the pd-select element and the pd-card element. We are now in a position to implement a more advanced grid system. In the next module we'll finish the staff page by creating a more complicated page with a grid to view, create, update, delete, search, and sort the staff list.
Staff List Page
Hi there. In this section, we'll create together the staff list page. This will be a grid with the staff information where we'll list the staff, create a new staff member, update the info of a staff member, delete an item, and search members by their username. Let us dive in.
Reading the Data
In this video, we'll create the staff page, our grid, and list the staff data. The first step is to create a folder named staff. Our html page staff.html, html page for our element, staff-list.html, and the staff.css file. In the staff.html I'll include the staff-list element and add the staff-list element. Now in the staff-list.html element page I'll add the element boilerplate and include the elements I'll use in this element. I'll open the staff.css page and add some custom CSS, and include the styles in my element. You can find this code in the demo of the module. The next step is to include some styles with my global variables. Let us add the pd-card element and in this element I'll set my grid. The grid has a head section and a body section. The head section works just like a html table would and the body section has a template loop that loops through the profile array and for each item will display the appropriate properties. The third step will be to include the iron-ajax element so we can make an AJAX request at my REST service with that element and get the profiles necessary to display. If I load the path in my browser you can see the JSON array that is returned. Time to load this in our code. I'll create two new methods. The searchProfiles and the searchProfilesCallback. In the ready method callback, I'll call the searchProfiles method and in this method I'll trigger the iron-ajax request. The iron-ajax request will handle the request at the url specified and once we have a response it will call the searchProfilesCallback method with the response. In the searchProfilesCallback I'll associate the response data with the profiles array and for each item in the array, I'll set a new property called selected. After reloading the page, we can successfully view the list of the staff members. This grid could use some more improvements such as pagination, but for this demo we'll keep things simple. Things are looking great. In this next video we'll see how we can set up a create form to add new staff members to our list.
Creating the Data
In this video we'll create a mobile friendly form to add new staff members to our list. First of all, in my elements properties I'll add two new properties named editModel which is an object and panelToggle, which is a string. In my elements template I'll add the panel snippet. In this snippet we have the binded class attribute which changes the divs class attribute according to the panelToggle parameter. In the body of our panel we have a form where each value is binded to a property of the editModel object. Also, it has two buttons, the save and the close button, where the save button will be used to save our form and the cancel will be used to close the panel without saving. Then in our grid section I'll add an options line to add various buttons for my grid. In this section we'll include an add button to open our panel. This button has an on-tap trigger that will run the openPanel method every time we click on the button. The last element that we'll add in our template is another iron-ajax element, used to trigger a save request to our server to persist the save data. This is a post request at the following url and once the request is done, it will trigger the saveProfileCallback method. At this point we have four triggers unhandled. First, the on-tap method named openPanel to open our panel. The second, the saveProfile method to trigger the save action. Third, the closePanel trigger to just close the panel. And last, the saveProfileCallback method to do something once a new staff member is added. I'll start with the open panel to show my panel. To do this, I'll just set the panelToggle property to toggled. Also, I'll instantiate the editModel object. As seen previously, the panelToggle property is binded with the class attribute over here, so it will set the class to the string toggled. If we view in our CSS, we can see that the edit panel which has a parent with the class toggled, will move the panel to the X axis from -200 to 0. Then, in the closePanel method I'll set the panelToggle to empty so that will change from 0 to -200 again. Let me refresh my page to see the results. Once I click on the + sign, the panel glides into view and once we click on the close button, the panel glides out of view again. Now we want to save our member when the user clicks on save. In the saveProfile method I'll set the body of my request to the editModel object. Set the content type to application JSON and trigger the request. Once the request is done, the callback is triggered where we'll set a toast message, reload our list, and close the panel. Lastly, let me add the paper-toast element as well in my page. I'll refresh my page and click on the add sign again. Let us add some dummy data and click save. (typing) The new user is added, the toast message is displayed, and the panel closes. In my debugger you can see the post request set the iron-ajax element. In the body of the request is the new user in JSON format and we can have a response of that user with the new id which indicates that everything went as expected. Then we can see the get request again that is triggered to refresh our list. Also, you notice an options request before my post request. This is just something that iron-ajax elements does which works as a ping before the post to be sure everything is okay with the server before it sends the data. In the next video we see how we can update the data of the user that is already in the list.
Updating the Data
For each user in our list you can notice an edit button that binds the id of the user with the data id attribute and once clicked, it triggers the openPanel method again. I will expand my openPanel method to handle this functionality as well. From the event object we'll get the html node where the event was triggered from. From that element, we'll get the id from the data-id attribute and set properties of the editModel the same of those from our profile list that has that same id. If the data-id attribute doesn't exist, then the id value will be null, so then we'll reset the editModel to empty values. If I go back to the html section of my element, you can see that when the user clicks on an add button, the openPanel method is triggered, but the data-id attribute doesn't exist so the values will be empty, but at the edit button, the data-id has the value of the staff member's item, so the edit-model will be this item. Last, when the user clicks on the save button, then we don't have to do anything because we'll send to the server the editModel item again which will be the updated data of the user. To preview this in action, I'll reload my list page again and click on the edit button. Change the type from itadmin to teacher and click on save. In my debugger you can see the post request made with the data of my user. The server will know that this is an existing user because we have the id property set to a preexisting value. Now if I click on the add button and add some dummy data, click on save, (typing) you can see the same request made, but the id property doesn't exist so the server knows that this is a new user and add the user in our database as a new user. In both cases, after the request, the list refreshes. We're going very well, as we can create, read and update our staff list. The last step is to be able to delete a user so we can have a simple, crude implementation set.
In this video, we'll add the delete functionality to our grid. In our loop we can see that each item has a selected property that is binded to the paper-checkbox element. So every time we click on an element, the selected property from false is set to true. We'll add a new item in our options section, which will trigger the deleteProfiles method. Last, for our html section, I'll add a new iron-ajax element with the information needed to our delete request. The url is the localhost5000/profiles path again, but the method is delete and the response callback is the deleteProfilesCallback method. Time to handle these two triggers. The deleteProfiles method which is triggered from the delete button, will loop through the profiles and if one is selected, it will add the id of that user at the end of our url and trigger the request. In our callback method, we'll show a toast message and refresh our list and close the panel if it is open. You can, of course, improve this section by creating an array and making the request once instead of making different delete requests for each member you want to delete. Let me refresh the page and select the two items we added in the previous videos and click on the delete button. We can see that these two items have been removed successfully. If we call our REST service as well, we can see that these items have been moved from the backend as well. Now that we have a basic grid where we can list, add, edit, and delete an item from a list, it is time to push the envelope a bit forward and add a search feature.
In this video we'll include a search feature in our grid. I'll make this section a bit more advanced since by now you should have a really good grasp on how things work. In reality, when you're working with Polymer, you want to break things down into small, reusable, testable, and independent components. So I want to add a search component to my list. This will basically be a search button that once clicked, it will take all of its parent's element's space. Then we can enter some text and click on the enter button to search or click on the exit button to close the search box. I'll create a new component named pd-search that will have this functionality. As always, the pd-search.html will have the element boilerplate code to instantiate my element. I'll include the other elements needed and move on to my dom-module section. I'll include some custom styles. You can copy and paste the styles from the demo files of this module. In the template tag of our element, for now we'll just add a search button. Let me include the pd-search in my list page and add the element in the list options. After refreshing the page, you can see the search button there. Of course, if we click on it, nothing happens. I'll wrap the button with a div and bind the class attribute of that div with the overlayClasses property. I'll also add the search-form in my wrapper. In my properties section I'll include the search-enabled Boolean property and the overlayClasses property. The overlayClasses property will be computed, triggering the computeClass method dependent on the search element property. Every time now the search enabled property changes, the computedClasses method will be triggered and set the overlayClasses value to search overlay, if the search-enabled is true, else it will set it to search hidden. In our CSS when the search-hidden is visible the search-form is hidden and when the search-overlay class is visible the search button is set to the left of our box. When the search button is clicked we'll add a method named search to handle this event. In this event we'll set the search-enable to true. Focus the input in our input element and set the value to empty. Last, when the close method is triggered, we'll set the search-enable to false. I'll refresh the staff page to see the search box in action. Once we click on the search button, you can see the search box appearing and once we click on the x button, you can see that the search box disappears.
Search Element - Custom Events
In this video we'll see how we can connect the pd-search element with our list. I'll include a special element created by the Polymer Team named iron-a11y-keys. With this element we can set a target and once one of the keys set is hit, a method will be triggered. In our case we'll target the search-form div and once the enter key is triggered, while we are focused in this div, the search-action method is triggered. Now in the search-action method we'll run the fire method. If you visit the following path, you can find some helper functions by Polymer. The fire function fires a custom element. The first property is a string first to declare the event name. In the second property we can add any custom values we want to pass over through our event and the third property are some other special properties such as bubbling and other special parameters we can preview here. Going back to our code, we can see that the search action will fire a custom element with the name of search and as a value, the value of the search input tag. Also, we'll fire a searchClosed custom element once the search box is closed. To handle these events we'll have to add two event listeners in our staff list page. These handlers will be attached to the search elements. In the fire element, the this section indicates the whole element so the handler will be attached to the pd-search element as well. So let me return to the event handler. In the callback function, the event variable is passed that has many interesting properties. The detail property is the custom variable passed from our fire events, which in our case is a search value. We'll run the searchProfiles method passing this value. In the searchClosed event, we'll just run the searchProfiles method to refresh our list. Lastly, I'll expand the searchProfiles method to handle a search parameter. I'll add the parameter in my inputs. If the search parameter is not null, we'll add the parameter in our request for our username. If it is null, we'll reset the parameters. Time to see if everything is okay. I'll refresh the page and click on the search button. Let us add Bill and click enter. You can see the filtered list. If I add joy and click enter, the members with username with joy appear. Once we click on the x button, the search form closes and our list refreshes with no parameters as expected.
Search Element - Reuse
In this video we won't add a new feature but I'll just show you how we can reuse the search element we just created. Let us say that we want to add a search feature on the header of our page. We'll see how easy it is to do this while reusing our component. I'll open the pd-drawer.html element and include the search element. Then I'll add the pd-search element on the toolbar of my page. Have in mind that the element has the id of search. I'll refresh the page to see what's going on. You can see the search icon on the right of the page. Once I click on it, the search form appears and once I click on the x button, it disappears. Once I click on the search button in the list page we created previously, we can notice the same functionality. With this example, you can see in action how we can use the same element we created together in two parts of the page. These are two separate entities with the same functionality. To handle events in our header's search element, I'll add two event handlers in my ready callback. These handlers are attached on the search element. To select the search element you can write this, which is the whole element, the $ which is the template element of our element, and the search which is the id of the pd-search element. For now I'll add two console.log methods to write messages in the debug console. I'll reload the page again and click on the header's search element again. Once I enter some text and click on the enter button, you can see the search term in my console.log. You could do anything you would like from here on, either load a search page, filter a search term, anything. Lastly, once we close the search, you can see the closed message in the console log, meaning that the closed event was triggered.
In this module we put together a grid with some basic crude functionalities where we can create a staff member, read a staff member, update the staff members, and delete the staff members. Lastly, we created our own search element for our staff list and we saw how we can reuse the element in other parts of the page. In the next module we'll see how we can construct a simple chat system in our application.
This is the last module of this course concerning features of our application. We will list our friends on the right panel of the page and once we click on of our friends, we can chat with them. To make this possible we will see how we can add real-time functionality to our application and how can we create a simple chat system.
The first step for a chat is to list the friends or list the people that we can chat with. I'll open the pd-dashboard element and in the properties of our page add an array that will include our friends. Also, we'll add an iron-ajax element that has the details needed to make a request to the server to obtain the data of our friends. The url is localhost5000/friends. It is a get request and once the data is received we'll call the getFriendsCallback method. We'll need also our profile information so I'll add another iron-ajax request. The iron-ajax element has an attribute for auto which means that it will trigger a request automatically once the element is loaded and once we have the response it will call the getProfileCallback method. Let me copy the url of the request and make the request from our browser to see what data will return. From this request we'll need the username so we can use it for our second request. The second request will call the localhost5000 friends url and add as a parameter the username retrieved from the previous request which is Bill. So once we call the url you can see the friends of the user Bill. Time to do this in our code. I'll first create a method for my callback and grab the username from that response. Then we'll call the getFriends method where it will set up the username parameter in my request and trigger the getFriendsRequest. Last, from my callback I'll set the friends property to the array of friends from the response and for each of those items set a url parameter. To show the friends loaded in the right drawer I'll create a template repeat element in the right menu section and add the pd-list-item element for each item in the loop, by adding the url attribute with the url parameter set and the name of my friend. After reloading the page you can see the friends of the user appearing on the right of the page. If I click on one of them, nothing happens, as we haven't created the thread page yet. We'll create that chat page in the next video.
In this video we'll create the thread page. I'll create a new folder named thread and in it three files, the thread.html which is the page loaded, the thread.css to save my styles, and the thread list which will be the element loaded in the page. In the thread.css I'll add some custom CSS. You can find this code in the demo files of this module or in the polymer-dashboard.com project. And in the thread.html I'll load the thread-list element with the link tag and add the thread-list element in my page as well. In the thread-list element page I'll insert the standard element boilerplate code and include the link of the elements I'll be using. I'll include the CSS file and some custom styles using the global CSS variables we have set in the stylings module of the course. Now the chat page will have two sections. The first will loop through the messages and display some data such as the user, the message, and the date time of the message, and it will have a footer section which will work as an input for us to write our messages, and a send button to trigger the send message event. In the properties section, I'll Active Directory the messages array to carry the messages in the thread, a message string which will be the message we'll be sending from the input tag, our username, and the conversation key. In the bottom of the template element we have added a getProfile request to trigger automatically and once we have a response, the getProfileCallback method will be triggered. In the getProfileCallback we'll set the username from the response, instantiate the message and get the username of the person we're chatting with from the url parameters of the page. Lastly, we'll create the conversation id which will be the username of the users in the conversation in alphabetical order. This way both sides have the same id while chatting. In this video we created the basic structure for our chatting mechanism. In the next video we'll see how we can send and receive data in real time.
In this video we'll install and set up socket.io. To make a web application have real-time features you have to use a pile of techniques such as long-polling, the Forever-frame technique, server-send events or WebSockets. To learn more about the basics of real-time web applications you can view my course with the title, Real-time Web Applications, to dive deep in the theory behind these techniques. Usually we don't have to dive into these techniques but use high-level libraries such as SignalR for .NET applications or socket.io for NodeJS applications. Since we're using NodeJS for our backend we'll be using socket.io. To do this, we'll have to open the package.json file and include the socket.io library. Then we'll run npm install to download the package. After that we'll open the app.js file and scroll to the end. I'll instantiate the I/O object, adding as a parameter the http server. Then after a client has connected we'll add two event handlers, the on subscribe and the on chat message. These two handlers will be triggered from events emitted from the client side. The first one is to subscribe the user in a room. The second one is to broadcast the message to the members of the room, so we'll parse the message to JSON format and emit a private message event to the client side of the members of the room when the user sends a new message. The server side of our code is ready so we'll go over to the client side in the next video. For more information on socket.io you can visit socket.io or its GitHub page at: github.com/socketio/socket.io.
Updating Data in Real-time
Now I'll go to the client side. First of all we'll load the socket.io client library. Then we'll create a socket object in our properties. We'll instantiate it in the getProfileCallback method which as you remember runs automatically once we have the user profile information. Then we'll emit the subscribe event with the conversation id. After that we'll create an event handler for the private message event sent from the server. This handler will trigger every time the server receives a new message for the room. So we'll parse the message, push it in our messages array and scroll the wrapper to the bottom. You'll notice that the scroll code is located in this function. The async is used in Polymer to run code asynchronously after x amounts of milliseconds. I've added the scroll code in an async method so the rendering of the new message we just pushed can be rendered before we scroll. We finish the part of the code where we subscribe into a room and receive messages from the server in real time. Time to create the functionality of sending a message. You remember that we had a send button. Let me see what method does that trigger. It triggers the sendMessage method. I'll create that method in my scripts section. First of all, I'll add the check not to do anything if the method is empty. Then we'll get the date and time and stringify a JSON object with the parameters of the user, the room, the message, and the date. We are stringifying the JSON object because we have to send strings to the server. Then we emit the chat message event to the server with that string and reset the message. I've split the screen in two for you to view the server side and client side. You can see that first of all the user will trigger the subscribe event from the client to the server. Then once it triggers the chatMessage event from the client to the server that will trigger the private message event from the server to all of the subscribed clients, so it will update to all of the clients. Time to view our demo in real action. I'll run the server and reload the page. You can preview my friends on the right panel of the page. Now I'll open a new private tab and log in as the user Joy. You can see her friends as well. I'll click on Joy in one account and Bill on another. When I send a message from one account, you can see that it is appearing in both windows instantly. Now if I click on another friend, let's say George, you won't see the message in the conversation with Joy, which is logical since this conversation has the id of bill-joy and the other one has the id of bill-george.
In this module we created a very simple chat system and added real-time functionality in our application. There are some security optimizations that you can consider making such as setting up the subscription on the server side and adding authentication checks on the server side as well, but we can leave this simple demo as it is and you can take it from here. This was the last feature of our application and we could send it to our client as it is right now; however, in the next module we'll talk about performance and optimization to make our application faster, smaller, and more stable.
Performance and Optimization
In this module we'll talk about performance and optimization. Our application may look like it's done; however, there are some techniques left for us to improve its speed and make it smaller. Also, we'll have to add some tests for the durability, longevity and stability of our application.
Vulcanization - The Problem
Vulcanization - The Solution
With vulcanization we can run a compiler script on the html file of the element we wish. This script will go through the element and find all of the resources needed. Once it finds a resource it will load it and append it in the file. It will run this recursively in the elements included as well and it will find resources in them, it will append those as well. This way we will have one big html file instead of tens of small files. I'll open the package.json file and add the gulp-vulcanize task. Then in the gulp-file.js file I'll include a copy task which will copy the pd-dashboard element and paste it to the new file, pd-dashboard.vulcanize.html. Then we'll set up the vulcanize task to run the vulcanization process on the pd-dashboard.vulcanize.html file. In the exclude array I'll add the files I want to exclude from the vulcanization process. Usually we want to load the Polymer project externally, to load asynchronously. Then we'll set some more properties such as stripComments if you want to remove the comments from our code, inlineCss to embed or not the CSS reference in our page. I'll set this attribute to false so I can load them externally. InlineScripts to embed all of the scripts in one page and finally scriptExcludes to exclude some scripts from the vulcanization process. For the full list of properties and accommodation for the gulp-vulcanize task, you can visit the following link. We'll also have to include our vulcanize task in the default run sequence. I'll open Git Bash and run npm install to download the module. And then run Gulp to run the vulcanized task we just created. Lastly, in the index.html file we'll load the vulcanized file and not the pd-dashboard-html file. If I open pd-dashboard.vulcanize.html, you can see a big html file with all of the resources included. I'll start the server now and refresh the page. Everything has loaded as usual. You can see that the requests are fewer. Imagine now thousands of users using our site. We have saved thousands of requests from our server, making our site faster and relieving a great load from the wire.
In this module we didn't add any more features to our application. We went although through some performance issues we may come across and saw ways to solve them and optimize the application. Lastly, we saw how we can create tests for our custom elements and make reliable and performant Polymer applications.
Caveats and Resources
This is the last module of this course and we'll talk about why you may not want to use Polymer in your applications. We'll also go through the interesting differences between the Shady DOM and the Shadow DOM. Lastly, I'll list resources where you can continue your journey on Polymer and that you may find helpful to learn more on this subject.
A first reason you may not want to use Polymer is browser compatibility. If you visit the browser compatibility matrix, you'll notice very quickly that Polymer wasn't created for old browser support in mind. It basically works perfectly for IE11 and above and for the latest version of the other browsers such as Chrome, Firefox, and Safari. Most features work on IE10 as well and I've made some small demos work on IE9 as well. So if you are intending to use Polymer for the general public, you must have this in mind. If you use Polymer for a more controlled group of target groups that consist of mostly experienced users, you won't have a problem. For more info about browser compatibility, you can follow the Polymer team as they make more updates on this issue.
Shady and Shadow DOM
Resources - Next Steps
For the last video of this course I would like to share some interesting resources I've come across while learning and working with Polymer. The first one of course is the official Polymer JS website. The second site is elements.polymer-project.org where you can find numerous elements made by the Polymer team. Of course, the Polymer Twitter page, the Polymer Slack channel where you can come in content with members of the team and have a more inside look into conversations and ideas about the future of Polymer. The Polycasts series which is a YouTube video series by Rob Donson on Polymer. I find these videos excellent and extremely resourceful. The Polymer Google+ page, the Polymer Starter Kit project, which we already mentioned in the beginning of the course. This is a starter project for your Polymer applications, having a number of problems already addressed such as the routing and your site's architecture. The polymer-dashboard project which is an open source project I'm working on. It is basically a fully working Polymer dashboard so you can use it and build on it if you're thinking of creating a Polymer dashboard. Lastly, you can visit webcomponents.org which is the main site for Web Components. And of course, Pluralsight's course on Web Components created by my friend Cory House. I've already watched his course and it's definitely amazing and I highly recommend it to go even deeper in the technologies we used.
This is the end of our course on building a web application with Polymer JS and Material Design. I hope you enjoyed watching this course as much as I enjoyed recording it. We created together a full-blown application with the use of Polymer JS stepping on the Material Design principles. While creating this application we went through the basics of Polymer and got accustomed with the principles of Web Components. I can't wait to see what you'll be doing with the Polymer JS library from here on and I would love to hear from anyone who wants to reach me on the discussion panel of the course. Thank you and see you on the next one.
Bill is a Microsoft MVP, Google Developer Expert, a Senior Software Engineer at Software Competitiveness International, and the creator of Dotnetweekly. He has over 7 years of experience in...
Released14 Dec 2015