{"id":43446,"date":"2016-10-03T20:52:43","date_gmt":"2016-10-03T17:52:43","guid":{"rendered":"https:\/\/www.altoros.com\/blog\/?p=43446"},"modified":"2019-05-26T18:10:59","modified_gmt":"2019-05-26T15:10:59","slug":"how-to-create-a-page-layout-and-login-by-using-predix-ui","status":"publish","type":"post","link":"https:\/\/www.altoros.com\/blog\/how-to-create-a-page-layout-and-login-by-using-predix-ui\/","title":{"rendered":"How to Create a Page Layout and Login by Using Predix UI"},"content":{"rendered":"<p>Predix provides several <a href=\"http:\/\/predixdev.github.io\/predix-ui\/?show=landing_page&#038;type=home\" target=\"_blank\" rel=\"noopener noreferrer\">UI components<\/a> that help you to build web apps faster and easier. The components are implemented with <a href=\"https:\/\/www.polymer-project.org\/\" target=\"_blank\" rel=\"noopener noreferrer\">Polymer<\/a>, a lightweight library built on top of <a href=\"https:\/\/www.webcomponents.org\/\" target=\"_blank\" rel=\"noopener noreferrer\">WebComponents<\/a>, and can be integrated with other Predix services, such as <a href=\"https:\/\/www.altoros.com\/blog\/collecting-time-series-data-with-predix-a-golang-api-wrapper-included\/\">Time Series<\/a>.<\/p>\n<p>&nbsp;<\/p>\n<div id=\"ez-toc-container\" class=\"ez-toc-v2_0_79_2 counter-hierarchy ez-toc-counter ez-toc-transparent ez-toc-container-direction\">\n<div class=\"ez-toc-title-container\">\n<p class=\"ez-toc-title\" style=\"cursor:inherit\">Table of Contents<\/p>\n<span class=\"ez-toc-title-toggle\"><a href=\"#\" class=\"ez-toc-pull-right ez-toc-btn ez-toc-btn-xs ez-toc-btn-default ez-toc-toggle\" aria-label=\"Toggle Table of Content\"><span class=\"ez-toc-js-icon-con\"><span class=\"\"><span class=\"eztoc-hide\" style=\"display:none;\">Toggle<\/span><span class=\"ez-toc-icon-toggle-span\"><svg style=\"fill: #999;color:#999\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" class=\"list-377408\" width=\"20px\" height=\"20px\" viewBox=\"0 0 24 24\" fill=\"none\"><path d=\"M6 6H4v2h2V6zm14 0H8v2h12V6zM4 11h2v2H4v-2zm16 0H8v2h12v-2zM4 16h2v2H4v-2zm16 0H8v2h12v-2z\" fill=\"currentColor\"><\/path><\/svg><svg style=\"fill: #999;color:#999\" class=\"arrow-unsorted-368013\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"10px\" height=\"10px\" viewBox=\"0 0 24 24\" version=\"1.2\" baseProfile=\"tiny\"><path d=\"M18.2 9.3l-6.2-6.3-6.2 6.3c-.2.2-.3.4-.3.7s.1.5.3.7c.2.2.4.3.7.3h11c.3 0 .5-.1.7-.3.2-.2.3-.5.3-.7s-.1-.5-.3-.7zM5.8 14.7l6.2 6.3 6.2-6.3c.2-.2.3-.5.3-.7s-.1-.5-.3-.7c-.2-.2-.4-.3-.7-.3h-11c-.3 0-.5.1-.7.3-.2.2-.3.5-.3.7s.1.5.3.7z\"\/><\/svg><\/span><\/span><\/span><\/a><\/span><\/div>\n<nav><ul class='ez-toc-list ez-toc-list-level-1 ' ><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-1\" href=\"https:\/\/www.altoros.com\/blog\/how-to-create-a-page-layout-and-login-by-using-predix-ui\/#Getting_started\" >Getting started<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-2\" href=\"https:\/\/www.altoros.com\/blog\/how-to-create-a-page-layout-and-login-by-using-predix-ui\/#Layout\" >Layout<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-3\" href=\"https:\/\/www.altoros.com\/blog\/how-to-create-a-page-layout-and-login-by-using-predix-ui\/#Login\" >Login<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-4\" href=\"https:\/\/www.altoros.com\/blog\/how-to-create-a-page-layout-and-login-by-using-predix-ui\/#Further_reading\" >Further reading<\/a><\/li><\/ul><\/nav><\/div>\n<h3><span class=\"ez-toc-section\" id=\"Getting_started\"><\/span>Getting started<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>If you are interested in an already working application that uses Predix UI components, see <a href=\"https:\/\/github.com\/PredixDev\/predix-seed\" target=\"_blank\" rel=\"noopener noreferrer\">predix-seed<\/a>. It is a small AngularJS dashboard app (with some Nginx back-end code written in Lua for supporting UAA login). It employs  Predix UI layout and a few other elements. To get started with the Seed app, just clone it, run <code style=\"color: #222222; background-color: #e6e6e6; padding: 1px 2px;\">npm install && bower install<\/code>, and start the server with the <code style=\"color: #222222; background-color: #e6e6e6; padding: 1px 2px;\">grunt serve<\/code> command.<\/p>\n<p>Alternatively, you can use my minimalistic <a href=\"https:\/\/github.com\/gekola\/px-ui-experiments\/tree\/master\/01-px-login-uaa\" target=\"_blank\" rel=\"noopener noreferrer\">px-login demo app<\/a>, which has a more traditional <a href=\"https:\/\/expressjs.com\/\" target=\"_blank\" rel=\"noopener noreferrer\">Express.js<\/a> back end and fancy <a href=\"https:\/\/pugjs.org\" target=\"_blank\" rel=\"noopener noreferrer\">Pug<\/a> for HTML templates.<\/p>\n<p>For building and running the application, I used <a href=\"https:\/\/gruntjs.com\/\" target=\"_blank\" rel=\"noopener noreferrer\">Grunt<\/a> tasks that were mostly imported from the seed application. To start my application in the development environment, the following steps are performed:<\/p>\n<ol>\n<li>Pug templates are compiled into HTML files.<\/li>\n<li>The Express server is started, serving static files, as well as API endpoints.<\/li>\n<\/ol>\n<p>In the production environment, the following additional steps, which  should be taken between the previous two, are required:<\/p>\n<ol>\n<li>The Polymer loader is vulcanized, producing a single file that contains all the required components instead of the default one or multiple files per component.<\/li>\n<li>Static files\u2014HTML pages and several scripts\u2014are copied to the distribution directory.<\/li>\n<\/ol>\n<p>For managing front-end packages, both the Seed and my applications use <a href=\"https:\/\/bower.io\/\" target=\"_blank\" rel=\"noopener noreferrer\">Bower<\/a>.<\/p>\n<p>The configuration of Grunt plugins can be found in the <code style=\"color: #222222; background-color: #e6e6e6; padding: 1px 2px;\">tasks\/options<\/code> folder. The Seed project splits the configuration into several files: one per plugin. My application stores them altogether in <code style=\"color: #222222; background-color: #e6e6e6; padding: 1px 2px;\">tasks\/options\/index.js<\/code>.<\/p>\n<p>&nbsp;<\/p>\n<h3><span class=\"ez-toc-section\" id=\"Layout\"><\/span>Layout<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>In Predix UI, it is assumed that your application follows the styling defined in <em>px-theme<\/em>. Below you can find how a bare-minimum application page with Predix UI looks like.<\/p>\n<p>The <code style=\"color: #222222; background-color: #e6e6e6; padding: 1px 2px;\">public\/index.html<\/code> file:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">&lt;!DOCTYPE html&gt;\r\n&lt;html&gt;\r\n  &lt;head&gt;\r\n    &lt;meta charset=&quot;utf-8&quot;&gt;\r\n    &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot;&gt;\r\n    &lt;title&gt;Title&lt;\/title&gt;\r\n    &lt;script src=&quot;bower_components\/px\/dist\/px.min.js&quot;&gt;&lt;\/script&gt;\r\n    &lt;script src=&quot;bower_components\/es6-promise\/es6-promise.min.js&quot;&gt;&lt;\/script&gt;\r\n    &lt;script src=&quot;bower_components\/webcomponentsjs\/webcomponents-lite.js&quot;&gt;&lt;\/script&gt;\r\n    &lt;link rel=&quot;import&quot; href=&quot;polymer-loader.vulcanized.html&quot;&gt;\r\n  &lt;\/head&gt;\r\n  &lt;body class=&quot;app&quot; unresolved&gt;\r\n    &lt;header role=&quot;banner&quot;&gt;\r\n      &lt;div class=&quot;viewport&quot;&gt;Header&lt;\/div&gt;\r\n    &lt;\/header&gt;\r\n    &lt;div class=&quot;viewport&quot;&gt;\r\n      &lt;div class=&quot;content-wrapper&quot;&gt;\r\n        &lt;px-app-nav class=&quot;navbar&quot; nav-items=&quot;&#x5B;]&quot; path-prefix=&quot;#&quot; path-key=&quot;state&quot;&gt;\r\n        &lt;\/px-app-nav&gt;\r\n        &lt;main class=&quot;u-pt-- u-pr-- u-pl--&quot; role=&quot;main&quot;&gt;\r\n          &lt;section role=&quot;region&quot;&gt;&lt;\/section&gt;\r\n        &lt;\/main&gt;\r\n      &lt;\/div&gt;\r\n    &lt;\/div&gt;\r\n    &lt;footer class=&quot;flex flex--middle&quot; role=&quot;contentinfo&quot;&gt;\r\n      &lt;div class=&quot;viewport&quot;&gt;Footer&lt;\/div&gt;\r\n    &lt;\/footer&gt;\r\n  &lt;\/body&gt;\r\n&lt;\/html&gt;<\/pre>\n<p>The <code style=\"color: #222222; background-color: #e6e6e6; padding: 1px 2px;\">public\/polymer-loader.html<\/code> file:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">&lt;!DOCTYPE html&gt;\r\n&lt;link rel=&quot;import&quot; href=&quot;bower_components\/px-theme\/px-app.html&quot;&gt;\r\n&lt;link rel=&quot;import&quot; href=&quot;bower_components\/px-theme\/px-theme.html&quot;&gt;\r\n&lt;link rel=&quot;import&quot; href=&quot;bower_components\/px-app-nav\/px-app-nav.html&quot;&gt;<\/pre>\n<p>Here, <code style=\"color: #222222; background-color: #e6e6e6; padding: 1px 2px;\">index.html<\/code> contains the application layout, and <code style=\"color: #222222; background-color: #e6e6e6; padding: 1px 2px;\">polymer-loader.html<\/code> includes import declarations for all components that are used within the application. The header and footer content should be placed inside the corresponding <code style=\"color: #222222; background-color: #e6e6e6; padding: 1px 2px;\">.viewport<\/code> child elements.<\/p>\n<p>The mentioned code renders the following page:<\/p>\n<p><a href=\"https:\/\/www.altoros.com\/blog\/wp-content\/uploads\/2019\/05\/using-predix-ui-components.png\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.altoros.com\/blog\/wp-content\/uploads\/2019\/05\/using-predix-ui-components.png\" alt=\"using-predix-ui-components\" width=\"623\" height=\"345\" class=\"aligncenter size-full wp-image-43448\" \/><\/a><\/p>\n<p>The basic page sections are highlighted and labeled in the image above.<\/p>\n<p>The <em>px-app-nav<\/em> component is not supposed to have any user-provided elements except <em>px-login<\/em>. Its content is generated based on the <code style=\"color: #222222; background-color: #e6e6e6; padding: 1px 2px;\">nav-items<\/code> attribute value.<\/p>\n<p>&nbsp;<\/p>\n<h3><span class=\"ez-toc-section\" id=\"Login\"><\/span>Login<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>As its name implies, <em>px-login<\/em> is a Predix UI component responsible for providing a user with interactive means to log in. It is claimed to be easily integrated with UAA; however, the integration is not self-evident and requires four endpoints on your server side.<\/p>\n<p>Here is how the login component looks like for guest users:<\/p>\n<p><a href=\"https:\/\/www.altoros.com\/blog\/wp-content\/uploads\/2019\/05\/predix-ui-login-guest.png\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.altoros.com\/blog\/wp-content\/uploads\/2019\/05\/predix-ui-login-guest.png\" alt=\"predix-ui-login-guest\" width=\"162\" height=\"300\" class=\"aligncenter size-medium wp-image-43449\" \/><\/a><\/p>\n<p>Below is the page element displayed after signing in:<\/p>\n<p><a href=\"https:\/\/www.altoros.com\/blog\/wp-content\/uploads\/2019\/05\/predix-ui-login.png\"><img decoding=\"async\" src=\"https:\/\/www.altoros.com\/blog\/wp-content\/uploads\/2019\/05\/predix-ui-login.png\" alt=\"predix-ui-login\" width=\"162\" class=\"aligncenter size-full wp-image-43450\" \/><\/a><\/p>\n<p>The login process basically consists of the following steps:<\/p>\n<ol>\n<li>The user clicks the Sign In button that opens the <code style=\"color: #222222; background-color: #e6e6e6; padding: 1px 2px;\">\/login<\/code> page served by Express.js.<\/li>\n<p><\/p>\n<li>Express.js receives the <code style=\"color: #222222; background-color: #e6e6e6; padding: 1px 2px;\">\/login<\/code> request and redirects the user to the UAA login page.<\/li>\n<p><\/p>\n<li>UAA authenticates the user and redirects the browser to the <code style=\"color: #222222; background-color: #e6e6e6; padding: 1px 2px;\">\/auth_callback<\/code> endpoint served by Express.js, passing the authentication code in the query parameters.<\/li>\n<p><\/p>\n<li>The server generates a user token based on the authentication code. The token is saved to the session storage.<\/li>\n<p><\/p>\n<li>The server requests the user information from UAA. The information is saved to  the session storage.<\/li>\n<p><\/p>\n<li>Express redirects the browser back to the page, where the user was before the first step.<\/li>\n<\/ol>\n<p>The authentication token cannot be received during step 3, because the process requires client authentication and it is not secure to expose this information to the user. Generating the authentication code involves only the client ID, which can be exposed to the user without a significant risk.<\/p>\n<p>Here is how to process <code style=\"color: #222222; background-color: #e6e6e6; padding: 1px 2px;\">\/login<\/code> and <code style=\"color: #222222; background-color: #e6e6e6; padding: 1px 2px;\">\/auth_callback<\/code> requests:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">app.get('\/login', (req, res) =&gt; {\r\n  \/\/ For production hardcode\/check host otherwise you may risk leaking user session\r\n  const redirectUri = req.protocol + ':\/\/' + req.get('Host') + '\/auth_callback';\r\n  res.redirect(`${UAA_SERVER_URL}\/oauth\/authorize?response_type=code&amp;client_id=${CLIENT_ID}&amp;redirect_uri=${redirectUri}&amp;state=${req.query.state}`);\r\n});\r\n\r\napp.get('\/auth_callback', (req, res) =&gt; {\r\n  const redirectUri = req.protocol + ':\/\/' + req.get('Host') + '\/auth_callback';\r\n  const auth = {\r\n    user: CLIENT_ID,\r\n    pass: CLIENT_SECRET\r\n  };\r\n\r\n  request.post({\r\n    url: `${UAA_SERVER_URL}\/oauth\/token`,\r\n    auth,\r\n    form: {\r\n      code: req.query.code,\r\n      grant_type: 'authorization_code',\r\n      redirect_uri: redirectUri,\r\n      state: req.query.state\r\n    }\r\n  }, (err, response, body) =&gt; {\r\n    const authData = JSON.parse(body);\r\n    let token;\r\n\r\n    if (!err &amp;&amp; !authData.error) {\r\n      token = req.session.authToken = authData.access_token;\r\n\r\n      request.post({\r\n        url: `${UAA_SERVER_URL}\/check_token`,\r\n        auth,\r\n        form: {\r\n          redirect_uri: redirectUri,\r\n          token\r\n        }\r\n      }, (err, response, body) =&gt; {\r\n        if (!err) {\r\n          req.session.userInfo = JSON.parse(body);\r\n        }\r\n        res.redirect(req.query.state);\r\n      });\r\n\r\n    } else {\r\n      res.redirect('\/login');\r\n    }\r\n  });\r\n});<\/pre>\n<p>In this code:<\/p>\n<ul>\n<li><code style=\"color: #222222; background-color: #e6e6e6; padding: 1px 2px;\">UAA_SERVER_URL<\/code> is your UAA base URL.<\/li>\n<li><code style=\"color: #222222; background-color: #e6e6e6; padding: 1px 2px;\">CLIENT_ID<\/code> and <code style=\"color: #222222; background-color: #e6e6e6; padding: 1px 2px;\">CLIENT_SECRET<\/code> are the client ID and secret key.<\/li>\n<\/ul>\n<p>The <em>px-login<\/em> component receives user data through the <code style=\"color: #222222; background-color: #e6e6e6; padding: 1px 2px;\">\/userinfo<\/code> endpoint that  returns the data obtained in step 5 of the authentication process. (The component currently needs only <code style=\"color: #222222; background-color: #e6e6e6; padding: 1px 2px;\">user_name<\/code>.)<\/p>\n<p>Here is my code for handling the <code style=\"color: #222222; background-color: #e6e6e6; padding: 1px 2px;\">\/userinfo<\/code> request:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">app.get('\/userinfo', (req, res) =&gt; {\r\n  res.send(req.session.userInfo);\r\n});<\/pre>\n<p>For logging out, the session has to be reset, and the user should be redirected to <code style=\"color: #222222; background-color: #e6e6e6; padding: 1px 2px;\">UAA_SERVER_URL\/logout<\/code>. The code is below:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">app.get('\/logout', (req, res) =&gt; {\r\n  const redirectUri = req.protocol + ':\/\/' + req.get('Host') + '\/';\r\n  req.session.destroy((err) =&gt; {\r\n    res.redirect(`${UAA_SERVER_URL}\/logout?redirect=${redirectUri}`);\r\n  });\r\n});<\/pre>\n<p>Now, you have a working Polymer SPA with authentication capabilities. After reading this post, you might also want to think about how to implement routing and add actual content to your app using <a href=\"https:\/\/www.predix.io\/docs\/?r=638316#UeSZUkKm\" target=\"_blank\" rel=\"noopener noreferrer\">Predix cards<\/a> or plain components.<\/p>\n<p>&nbsp;<\/p>\n<h3><span class=\"ez-toc-section\" id=\"Further_reading\"><\/span>Further reading<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<ul>\n<li><a href=\"https:\/\/www.altoros.com\/blog\/introducing-cloud-foundry-cli-plugin-for-managing-predix-analytics-catalog\/\">Introducing Cloud Foundry CLI Plugin for Managing Predix Analytics Catalog<\/a><\/li>\n<li><a href=\"https:\/\/www.altoros.com\/blog\/how-to-configure-predix-analytics-services-and-use-them-from-a-node-js-app\/\">Using Predix Analytics Services from a Node.js App<\/a><\/li>\n<li><a href=\"https:\/\/www.altoros.com\/blog\/introducing-a-one-click-button-for-deploying-to-ge-predix\/\">Introducing a One-Click Button for Deploying to GE Predix<\/a><\/li>\n<li><a href=\"https:\/\/www.altoros.com\/blog\/collecting-time-series-data-with-predix-a-golang-api-wrapper-included\/\">Collecting Time Series Data with Predix (a Golang API Wrapper Included)<\/a><\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<hr\/>\n<p><center><small>The post was written by Nick Herman and then edited by Victoria Fedzkovich and <a href=\"https:\/\/www.altoros.com\/blog\/author\/alex\/\">Alex Khizhniak<\/a>.<\/small><\/center><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Predix provides several UI components that help you to build web apps faster and easier. The components are implemented with Polymer, a lightweight library built on top of WebComponents, and can be integrated with other Predix services, such as Time Series.<\/p>\n<p>&nbsp;<\/p>\n<p>Getting started<\/p>\n<p>If you are interested in an already working application [&#8230;]<\/p>\n","protected":false},"author":78,"featured_media":43447,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"content-type":"","footnotes":"","_links_to":"","_links_to_target":""},"categories":[214],"tags":[873,647],"class_list":["post-43446","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-tutorials","tag-cloud-native","tag-predix"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v26.6 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>How to Create a Page Layout and Login by Using Predix UI | Altoros<\/title>\n<meta name=\"description\" content=\"This tutorial explains the basics of using Predix UI, with a focus on page layout requirements and the px-login component.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.altoros.com\/blog\/how-to-create-a-page-layout-and-login-by-using-predix-ui\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"How to Create a Page Layout and Login by Using Predix UI | Altoros\" \/>\n<meta property=\"og:description\" content=\"Predix provides several UI components that help you to build web apps faster and easier. The components are implemented with Polymer, a lightweight library built on top of WebComponents, and can be integrated with other Predix services, such as Time Series. &nbsp; Getting started If you are interested in an already working application [...]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.altoros.com\/blog\/how-to-create-a-page-layout-and-login-by-using-predix-ui\/\" \/>\n<meta property=\"og:site_name\" content=\"Altoros\" \/>\n<meta property=\"article:published_time\" content=\"2016-10-03T17:52:43+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2019-05-26T15:10:59+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.altoros.com\/blog\/wp-content\/uploads\/2019\/05\/using-predix-ui-components-page-layout-login-v1.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"1027\" \/>\n\t<meta property=\"og:image:height\" content=\"595\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Nick Herman\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Nick Herman\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"7 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.altoros.com\/blog\/how-to-create-a-page-layout-and-login-by-using-predix-ui\/\",\"url\":\"https:\/\/www.altoros.com\/blog\/how-to-create-a-page-layout-and-login-by-using-predix-ui\/\",\"name\":\"How to Create a Page Layout and Login by Using Predix UI | Altoros\",\"isPartOf\":{\"@id\":\"https:\/\/www.altoros.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.altoros.com\/blog\/how-to-create-a-page-layout-and-login-by-using-predix-ui\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.altoros.com\/blog\/how-to-create-a-page-layout-and-login-by-using-predix-ui\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.altoros.com\/blog\/wp-content\/uploads\/2019\/05\/using-predix-ui-components-page-layout-login-v1.jpg\",\"datePublished\":\"2016-10-03T17:52:43+00:00\",\"dateModified\":\"2019-05-26T15:10:59+00:00\",\"author\":{\"@id\":\"https:\/\/www.altoros.com\/blog\/#\/schema\/person\/f18d50b9edfbcdc995be899e3edb42ff\"},\"breadcrumb\":{\"@id\":\"https:\/\/www.altoros.com\/blog\/how-to-create-a-page-layout-and-login-by-using-predix-ui\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.altoros.com\/blog\/how-to-create-a-page-layout-and-login-by-using-predix-ui\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.altoros.com\/blog\/how-to-create-a-page-layout-and-login-by-using-predix-ui\/#primaryimage\",\"url\":\"https:\/\/www.altoros.com\/blog\/wp-content\/uploads\/2019\/05\/using-predix-ui-components-page-layout-login-v1.jpg\",\"contentUrl\":\"https:\/\/www.altoros.com\/blog\/wp-content\/uploads\/2019\/05\/using-predix-ui-components-page-layout-login-v1.jpg\",\"width\":1027,\"height\":595},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.altoros.com\/blog\/how-to-create-a-page-layout-and-login-by-using-predix-ui\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.altoros.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"How to Create a Page Layout and Login by Using Predix UI\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.altoros.com\/blog\/#website\",\"url\":\"https:\/\/www.altoros.com\/blog\/\",\"name\":\"Altoros\",\"description\":\"Insight\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.altoros.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.altoros.com\/blog\/#\/schema\/person\/f18d50b9edfbcdc995be899e3edb42ff\",\"name\":\"Nick Herman\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.altoros.com\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/www.altoros.com\/blog\/wp-content\/uploads\/2016\/12\/328df9f-150x150.jpg\",\"contentUrl\":\"https:\/\/www.altoros.com\/blog\/wp-content\/uploads\/2016\/12\/328df9f-150x150.jpg\",\"caption\":\"Nick Herman\"},\"description\":\"Nick Herman is a software engineer at Altoros. He specializes in web development using Ruby and JavaScript as his primary tools. Nick also has professional interests and expertise in many other areas related to software engineering, including programming languages and cloud technologies. You can find him on GitHub.\",\"url\":\"https:\/\/www.altoros.com\/blog\/author\/nick-herman\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"How to Create a Page Layout and Login by Using Predix UI | Altoros","description":"This tutorial explains the basics of using Predix UI, with a focus on page layout requirements and the px-login component.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.altoros.com\/blog\/how-to-create-a-page-layout-and-login-by-using-predix-ui\/","og_locale":"en_US","og_type":"article","og_title":"How to Create a Page Layout and Login by Using Predix UI | Altoros","og_description":"Predix provides several UI components that help you to build web apps faster and easier. The components are implemented with Polymer, a lightweight library built on top of WebComponents, and can be integrated with other Predix services, such as Time Series. &nbsp; Getting started If you are interested in an already working application [...]","og_url":"https:\/\/www.altoros.com\/blog\/how-to-create-a-page-layout-and-login-by-using-predix-ui\/","og_site_name":"Altoros","article_published_time":"2016-10-03T17:52:43+00:00","article_modified_time":"2019-05-26T15:10:59+00:00","og_image":[{"width":1027,"height":595,"url":"https:\/\/www.altoros.com\/blog\/wp-content\/uploads\/2019\/05\/using-predix-ui-components-page-layout-login-v1.jpg","type":"image\/jpeg"}],"author":"Nick Herman","twitter_misc":{"Written by":"Nick Herman","Est. reading time":"7 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/www.altoros.com\/blog\/how-to-create-a-page-layout-and-login-by-using-predix-ui\/","url":"https:\/\/www.altoros.com\/blog\/how-to-create-a-page-layout-and-login-by-using-predix-ui\/","name":"How to Create a Page Layout and Login by Using Predix UI | Altoros","isPartOf":{"@id":"https:\/\/www.altoros.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.altoros.com\/blog\/how-to-create-a-page-layout-and-login-by-using-predix-ui\/#primaryimage"},"image":{"@id":"https:\/\/www.altoros.com\/blog\/how-to-create-a-page-layout-and-login-by-using-predix-ui\/#primaryimage"},"thumbnailUrl":"https:\/\/www.altoros.com\/blog\/wp-content\/uploads\/2019\/05\/using-predix-ui-components-page-layout-login-v1.jpg","datePublished":"2016-10-03T17:52:43+00:00","dateModified":"2019-05-26T15:10:59+00:00","author":{"@id":"https:\/\/www.altoros.com\/blog\/#\/schema\/person\/f18d50b9edfbcdc995be899e3edb42ff"},"breadcrumb":{"@id":"https:\/\/www.altoros.com\/blog\/how-to-create-a-page-layout-and-login-by-using-predix-ui\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.altoros.com\/blog\/how-to-create-a-page-layout-and-login-by-using-predix-ui\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.altoros.com\/blog\/how-to-create-a-page-layout-and-login-by-using-predix-ui\/#primaryimage","url":"https:\/\/www.altoros.com\/blog\/wp-content\/uploads\/2019\/05\/using-predix-ui-components-page-layout-login-v1.jpg","contentUrl":"https:\/\/www.altoros.com\/blog\/wp-content\/uploads\/2019\/05\/using-predix-ui-components-page-layout-login-v1.jpg","width":1027,"height":595},{"@type":"BreadcrumbList","@id":"https:\/\/www.altoros.com\/blog\/how-to-create-a-page-layout-and-login-by-using-predix-ui\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.altoros.com\/blog\/"},{"@type":"ListItem","position":2,"name":"How to Create a Page Layout and Login by Using Predix UI"}]},{"@type":"WebSite","@id":"https:\/\/www.altoros.com\/blog\/#website","url":"https:\/\/www.altoros.com\/blog\/","name":"Altoros","description":"Insight","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.altoros.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/www.altoros.com\/blog\/#\/schema\/person\/f18d50b9edfbcdc995be899e3edb42ff","name":"Nick Herman","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.altoros.com\/blog\/#\/schema\/person\/image\/","url":"https:\/\/www.altoros.com\/blog\/wp-content\/uploads\/2016\/12\/328df9f-150x150.jpg","contentUrl":"https:\/\/www.altoros.com\/blog\/wp-content\/uploads\/2016\/12\/328df9f-150x150.jpg","caption":"Nick Herman"},"description":"Nick Herman is a software engineer at Altoros. He specializes in web development using Ruby and JavaScript as his primary tools. Nick also has professional interests and expertise in many other areas related to software engineering, including programming languages and cloud technologies. You can find him on GitHub.","url":"https:\/\/www.altoros.com\/blog\/author\/nick-herman\/"}]}},"_links":{"self":[{"href":"https:\/\/www.altoros.com\/blog\/wp-json\/wp\/v2\/posts\/43446","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.altoros.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.altoros.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.altoros.com\/blog\/wp-json\/wp\/v2\/users\/78"}],"replies":[{"embeddable":true,"href":"https:\/\/www.altoros.com\/blog\/wp-json\/wp\/v2\/comments?post=43446"}],"version-history":[{"count":3,"href":"https:\/\/www.altoros.com\/blog\/wp-json\/wp\/v2\/posts\/43446\/revisions"}],"predecessor-version":[{"id":43453,"href":"https:\/\/www.altoros.com\/blog\/wp-json\/wp\/v2\/posts\/43446\/revisions\/43453"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.altoros.com\/blog\/wp-json\/wp\/v2\/media\/43447"}],"wp:attachment":[{"href":"https:\/\/www.altoros.com\/blog\/wp-json\/wp\/v2\/media?parent=43446"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.altoros.com\/blog\/wp-json\/wp\/v2\/categories?post=43446"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.altoros.com\/blog\/wp-json\/wp\/v2\/tags?post=43446"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}