-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathblog.json
54 lines (54 loc) · 672 KB
/
blog.json
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
{"index":{"_index":"blogs","_id":161220,"_type":"default"}}
{"id":161220,"date":"2017-11-01T16:00:29","date_gmt":"2017-11-01T23:00:29","guid":{"rendered":"https://www.sitepoint.com/?p=161220"},"modified":"2017-11-01T06:00:41","modified_gmt":"2017-11-01T13:00:41","slug":"how-to-deploy-node-applications-heroku-vs-now-sh","status":"publish","type":"post","link":"https://www.sitepoint.com/how-to-deploy-node-applications-heroku-vs-now-sh/","title":{"rendered":"How to Deploy Node Applications: Heroku vs Now.sh"},"content":{"rendered":"<p class=\"wp-special\">As Node.js continues to gain in popularity, new tutorials pop up teaching you to write server-side JavaScript apps and APIs. Once you’ve built your shiny new Node app, though, what then?</p>\n\n<p>In this article, I’m going to take a look at a couple of options for deploying your Node applications. We’ll take a look at <a href=\"https://zeit.co/now\">Now.sh</a> and <a href=\"https://www.heroku.com/\">Heroku</a>. </p>\n<p>I’ll explain how to deploy your code to each platform and we’ll end the article with a short summary of the pros and cons. I’ll pay attention to options for monitoring, ease of use, offered functionality and what the free hosting plan includes.</p>\n<h2 id=\"deploymentwithheroku\">Deployment with Heroku</h2>\n<p>To be able to deploy apps to Heroku, you will have to <a href=\"https://signup.heroku.com/login?redirect-url=https:%2F%2Fid.heroku.com%2Foauth%2Fauthorize%3Fclient_id%3Dd7d64563-92df-4ac1-9f8d-f980829ed7c3%26redirect_uri%3Dhttps%253A%252F%252Fdevcenter.heroku.com%252Fauth%252Fheroku%252Fcallback%26response_type%3Dcode%26scope%3Didentity%26state%3Dbe21ded529f687e1b089cd61ededeb1d600d9a030725b200\">sign up</a> at Heroku and <a href=\"https://devcenter.heroku.com/articles/getting-started-with-nodejs#set-up\">install the Heroku CLI</a> for your machine. I prefer working from my terminal!</p>\n<p>Before we can start, we need to add some code to the <code>Procfile</code>. Heroku makes use of this file to determine how to execute the uploaded code. </p>\n<p>The following code needs to be added to the file so Heroku knows what command should be executed to start the app:</p>\n<pre><code class=\"text language-text\">web: node app.js\r\n</code></pre>\n<p>Once this is done, try to log in from the terminal by typing <code>heroku login</code>. Heroku will ask you to enter your login credentials. </p>\n<p>Next, navigate to the root of your project and enter the command: <code>heroku create</code>. This creates an app on Heroku which is ready to receive the source code of your project. The name of the app on Heroku is randomly created. </p>\n<p>To deploy our code to Heroku, simply use <code>git push heroku master</code>. We can visit the app with the command <code>heroku open</code> which will open the generated URL.</p>\n<h3 id=\"pushingchangestoheroku\">Pushing changes to Heroku</h3>\n<p>Changes can be pushed by following the normal Github flow:</p>\n<pre><code class=\"bash language-bash\">git add .\r\ngit commit -m \"Changes made to app\"\r\ngit push heroku master\r\nheroku open\r\n</code></pre>\n<h3 id=\"usefulherokucommands\">Useful Heroku Commands</h3>\n<ul>\n<li>\n<p>To make sure that at least one instance of the app is running: <code>heroku ps:scale web=1</code><br />\nBecause we are using the free platform, it is not possible to upscale your application. However, it is possible to downscale so no instances of the application are running: <code>heroku ps:scale web=0</code></p>\n</li>\n<li>\n<p>View the latest logs (stream) in chronological order generated by Heroku: <code>heroku logs --tail</code><br />\nIt’s also possible to show the app logs only. App logs are the output of <code>console.log()</code> statements in your code and can be viewed with <code>heroku logs --source app-name</code></p>\n</li>\n<li>\n<p>Heroku provides the possibility to run your app locally at <a href=\"http://localhost:5000\">http://localhost:5000</a>: <code>heroku local web</code></p>\n</li>\n<li>\n<p>List all Heroku apps: <code>heroku apps</code></p>\n</li>\n<li>\n<p>Remove a deployment: <code>heroku apps:destroy --app app-name</code></p>\n</li>\n<li>\n<p>Add owner (account) to access the app: <code>heroku access:add [email protected]</code>, same for removing <code>heroku access:remove [email protected]</code></p>\n</li>\n</ul>\n<h3 id=\"herokuenvironmentvariables\">Heroku Environment Variables</h3>\n<p>If you are working with a <code>.env</code> file locally, you might want to use other environment variables for your Heroku deployment. It is possible to set these with <code>heroku config:set PORT=3001</code>. These values overwrite the variables set in you <code>.env</code> file. </p>\n<p>To see all defined Heroku environment variables, just use <code>heroku config</code>. If you want to remove an environment variable for e.g. <code>PORT</code>, use <code>heroku config:unset PORT</code>.</p>\n<h3 id=\"freeplan\">Free Plan</h3>\n<ul>\n<li>Allows up to five Heroku apps</li>\n<li>512 MB RAM</li>\n<li>No upscaling available, only one instance of app can be running at the same time</li>\n<li>Sleeps after 30 minutes of inactivity</li>\n<li>Randomly generated app names</li>\n<li><strong>Metrics about memory usage, response time and throughput available but not possible to add custom metrics</strong></li>\n</ul>\n<p><img src=\"https://dab1nmslvvntp.cloudfront.net/wp-content/uploads/2017/08/1503426911heroku-metrics.png\" alt=\"Heroku Metrics\" title=\"Heroku Metrics about mem usage, response time and throughput\" /></p>\n<h2 id=\"deploymentwithnowsh\">Deployment with now.sh</h2>\n<p>Now.sh focuses on the <strong>developer experience (DX)</strong>, which is kind of unique. They try to offer tools which are flexible and are incredibly easy to use. Now.sh is part of <a href=\"https://zeit.co\">Zeit.co</a> which have developed <a href=\"https://zeit.co/oss\">several tools</a>.</p>\n<p>To keep it simple, we will only install the Now.sh CLI through npm:</p>\n<pre><code class=\"bash language-bash\">npm install now -g\r\n</code></pre>\n<p>Next, we need to sign up so we can use our credentials in the console. Both login and sign up happen at the <a href=\"https://zeit.co/login\">login page</a>. Every time you sign in, you will have to confirm your login attempt by verifying through email. After confirming, you will be redirected to your dashboard where you can view your logs and deployments.</p>\n<p>To start using now, just type <code>now</code> in your console. The console will prompt your email. <em>Fill in</em> the correct email and verify this again by clicking on the verification email. </p>\n<p>Now we are logged in, let’s take a look at the start script in our <code>package.json</code>. Now.sh uses this to start the application. This is what the <code>scripts</code> field looks like:</p>\n<pre><code class=\"javascript language-javascript\">\"scripts\": {\r\n \"start\": \"node app\"\r\n},\r\n</code></pre>\n<p>Let us start with deploying our code to now.sh. Make sure you are in the root of the code example. To start the deployment process, <em>just hit</em> <code>now</code>. I think you can see the <strong>developer experience</strong> there. Everything can be executed with just one keyword! If you make changes to the application and you want to redeploy it, just hit <code>now</code> in your console and you are good to go. </p>\n<p>The URL of the app can be found in the console logs. More general logs about deployment or other now commands can be found at your <a href=\"https://zeit.co/dashboard\">dashboard</a>.</p>\n<p><img src=\"https://dab1nmslvvntp.cloudfront.net/wp-content/uploads/2017/08/1503426909deployment-with-now.sh_.png\" alt=\"Deployment with Now.sh\" title=\"Deployment with Now.sh\" /></p>\n<h3 id=\"customizationanddefiningenvironmentvariables\">Customization and defining environment variables</h3>\n<p>One way to customize your Now.sh deployment is by using a <code>now.json</code> file. However, since we are already using a <code>package.json</code> file, we can add the required customization under a the <code>now</code> key. This configuration allows you to customize the app name and alias, <em>set environment variables</em>, specify the deployment type and define the engine.</p>\n<pre><code class=\"javascript language-javascript\">\"now\": {\r\n \"name\": \"my-first-app\",\r\n \"alias\": \"app1\",\r\n \"type\": \"npm\",\r\n \"engines\": {\r\n \"node\": \"4.7.2\"\r\n },\r\n \"env\": {\r\n \"NODE_ENV\": \"production\",\r\n \"PORT\": \"3001\"\r\n }\r\n}\r\n</code></pre>\n<p>It’s also possible to set the environment variables through the CLI: <code>now -e NODE_ENV=\"production\" -e PORT=\"3001\"</code>.</p>\n<p>If you want to provide a dotenv file, you can set the option <code>now --dotenv</code>, but maybe you want to use <code>.env.production</code> instead of <code>.env</code>? This can be solved with <code>--dotenv=.env.production</code>. Lastly, you can also add the production dotenv file to your <code>package.json</code>.</p>\n<pre><code class=\"javascript language-javascript\">\"now\": {\r\n \"name\": \"my-first-app\",\r\n \"alias\": \"app1\",\r\n \"type\": \"npm\",\r\n \"engines\": {\r\n \"node\": \"4.7.2\"\r\n },\r\n \"dotenv\": \".env.production\"\r\n}\r\n</code></pre>\n<h3 id=\"usefulnowshcommands\">Useful Now.sh Commands</h3>\n<ul>\n<li>\n<p>The possibility to add an alias to your deployment: <code>now alias deploy-url aliasname</code></p>\n</li>\n<li>\n<p>List all deployments with their unique code: <code>now ls</code></p>\n</li>\n<li>\n<p>Remove a deployment: <code>now rm unique-code</code></p>\n</li>\n<li>\n<p>Force a new build (in case of issues): <code>now -f</code></p>\n</li>\n<li>\n<p>Scale your web app (free plan max 3): <code>now scale deployment-url 3</code>. Sometimes, it is not easy to predict the amount of traffic. Now.sh enables you to set auto scaling with a <code>min</code> and <code>max</code> value: <code>now scale deployment-url min max</code>.</p>\n</li>\n</ul>\n<h3 id=\"monitoringlogs\">Monitoring Logs</h3>\n<p>Log output can be retrieved with: <code>now logs [deployment-url | deployment-id]</code>. More advanced logging is also possible:</p>\n<ul>\n<li>\n<p><code>now logs -a -q \"GET\" -n 10 deployment-url</code>: Shows the 10 latest logs containing the word <code>GET</code>. </p>\n</li>\n<li>\n<p><code>now logs --since=20171028</code>: Shows all the logs from the 28th of October 2017 (ISO 8601 format)</p>\n</li>\n</ul>\n<p>It is also possible to access your logs by clicking on an app in your Now.sh dashboard.</p>\n<h3 id=\"ossplannowsh\">OSS plan Now.sh</h3>\n<p>The OSS plan is free to use and offers the following:</p>\n<ul>\n<li>Bandwidth: 1GB</li>\n<li>Log storage up to 100MB</li>\n<li>Infinite amount of deployments possible</li>\n<li>Concurrent instances is limited to 3</li>\n<li>No support for custom domains</li>\n<li>Max file size: 1MB</li>\n<li>No auto-scaling support</li>\n</ul>\n<h2 id=\"thebottomline\">The Bottom Line</h2>\n<p>Both Heroku and Now.sh offer great functionality. Now.sh focuses more on the developer experience by offering an easy to use CLI. On the other side, Heroku pays more attention to visual logging and especially monitoring with metrics. </p>\n<p>Personally, I prefer the simplicity Now.sh offers by just using one keyword <code>now</code> for (re)deployment. For Node apps, I like the addition of the <code>now</code> property to the <code>package.json</code> file to customize your Now.sh deployment. No need to add extra files like the <code>Procfile</code> Heroku requires. </p>\n<p>It’s hard to choose between both platforms. It just depends on your preferences and needs. Make sure to take a look at all the plans on offer. Good luck!</p>\n","protected":false},"excerpt":{"rendered":"<p class=\"wp-special\">As Node.js continues to gain in popularity, new tutorials pop up teaching you to write server-side JavaScript apps and APIs. Once you’ve built your shiny new Node app, though, what then?</p>\n<p>In this article, I’m going to take a look at a couple of options for deploying your Node applications. We’ll take a look at <a href=\"https://zeit.co/now\">Now.sh</a> and <a href=\"https://www.heroku.com/\">Heroku</a>. </p>\n<p>I’ll explain how to deploy your code to each platform and we’ll end the article with a short summary of the pros and cons. I’ll pay attention to options for monitoring, ease of use, offered functionality and what the free hosting plan includes.</p>\n<h2 id=\"deploymentwithheroku\">Deployment with Heroku</h2>\n<p>To be able to deploy apps to Heroku, you will have to <a href=\"https://signup.heroku.com/login?redirect-url=https:%2F%2Fid.heroku.com%2Foauth%2Fauthorize%3Fclient_id%3Dd7d64563-92df-4ac1-9f8d-f980829ed7c3%26redirect_uri%3Dhttps%253A%252F%252Fdevcenter.heroku.com%252Fauth%252Fheroku%252Fcallback%26response_type%3Dcode%26scope%3Didentity%26state%3Dbe21ded529f687e1b089cd61ededeb1d600d9a030725b200\">sign up</a> at Heroku and <a href=\"https://devcenter.heroku.com/articles/getting-started-with-nodejs#set-up\">install the Heroku CLI</a> for your machine. I prefer working from my terminal!</p>\n<p>Before we can start, we need to add some code to the <code>Procfile</code>. Heroku makes use of this file to determine how to execute the uploaded code. </p>\n<p>The following code needs to be added to the file so Heroku knows what command should be executed to start the app:</p>\n<pre><code class=\"text language-text\">web: node app.js\r\n</code></pre>\n<p>Once this is done, try to log in from the terminal by typing <code>heroku login</code>. Heroku will ask you to enter your login credentials. </p>\n<p>Next, navigate to the root of your project and enter the command: <code>heroku create</code>. This creates an app on Heroku which is ready to receive the source code of your project. The name of the app on Heroku is randomly created. </p>\n<p>To deploy our code to Heroku, simply use <code>git push heroku master</code>. We can visit the app with the command <code>heroku open</code> which will open the generated URL.</p>\n<h3 id=\"pushingchangestoheroku\">Pushing changes to Heroku</h3>\n<p>Changes can be pushed by following the normal Github flow:</p>\n<pre><code class=\"bash language-bash\">git add .\r\ngit commit -m \"Changes made to app\"\r\ngit push heroku master\r\nheroku open\r\n</code></pre>\n<h3 id=\"usefulherokucommands\">Useful Heroku Commands</h3>\n<ul>\n<li>\n<p>To make sure that at least one instance of the app is running: <code>heroku ps:scale web=1</code><br />\nBecause we are using the free platform, it is not possible to upscale your application. However, it is possible to downscale so no instances of the application are running: <code>heroku ps:scale web=0</code></p>\n</li>\n<li>\n<p>View the latest logs (stream) in chronological order generated by Heroku: <code>heroku logs --tail</code><br />\nIt’s also possible to show the app logs only. App logs are the output of <code>console.log()</code> statements in your code and can be viewed with <code>heroku logs --source app-name</code></p>\n</li>\n<li>\n<p>Heroku provides the possibility to run your app locally at <a href=\"http://localhost:5000\">http://localhost:5000</a>: <code>heroku local web</code></p>\n</li>\n<li>\n<p>List all Heroku apps: <code>heroku apps</code></p>\n</li>\n<li>\n<p>Remove a deployment: <code>heroku apps:destroy --app app-name</code></p>\n</li>\n<li>\n<p>Add owner (account) to access the app: <code>heroku access:add [email protected]</code>, same for removing <code>heroku access:remove [email protected]</code></p>\n</li>\n</ul>\n<h3 id=\"herokuenvironmentvariables\">Heroku Environment Variables</h3>\n<p>If you are working with a <code>.env</code> file locally, you might want to use other environment variables for your Heroku deployment. It is possible to set these with <code>heroku config:set PORT=3001</code>. These values overwrite the variables set in you <code>.env</code> file. </p>\n<p>To see all defined Heroku environment variables, just use <code>heroku config</code>. If you want to remove an environment variable for e.g. <code>PORT</code>, use <code>heroku config:unset PORT</code>.</p>\n","protected":false},"author":72575,"featured_media":135109,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[407,770],"tags":[9765,1717,9543,1535,11595],"_links":{"self":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/posts/161220"}],"collection":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/posts"}],"about":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/types/post"}],"author":[{"embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/users/72575"}],"replies":[{"embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/comments?post=161220"}],"version-history":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/posts/161220/revisions"}],"wp_featuredmedia":[{"embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/media/135109"}],"wp_attachment":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/media?parent=161220"}],"wp_term":[{"taxonomy":"category","embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/categories?post=161220"},{"taxonomy":"post_tag","embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/tags?post=161220"}],"curies":[{"name":"wp","href":"https://api.w.org/{rel}","templated":true}]}}
{"index":{"_index":"blogs","_id":161113,"_type":"default"}}
{"id":161113,"date":"2017-11-01T09:00:22","date_gmt":"2017-11-01T16:00:22","guid":{"rendered":"https://www.sitepoint.com/?p=161113"},"modified":"2017-10-26T20:50:16","modified_gmt":"2017-10-27T03:50:16","slug":"getting-to-know-your-users-with-analytics","status":"publish","type":"post","link":"https://www.sitepoint.com/getting-to-know-your-users-with-analytics/","title":{"rendered":"Getting to Know Your Users With Analytics"},"content":{"rendered":"<p><em>The following is a short extract from our book, <a href=\"https://www.sitepoint.com/premium/books/researching-ux-analytics\">Researching UX: Analytics</a>, written by Luke Hay. It’s the ultimate guide to using analytics for improved user experience. SitePoint Premium members get access with their membership, or you can buy a copy in stores worldwide.</em></p>\n<p>To understand why your users behave the way they do, you first need to get to know them. You may make assumptions about who those users are, but you should be constantly challenging those assumptions, or at least be backing them up with facts.</p>\n<p>There’s a lot of data available in your analytics package that will help build up your knowledge of who’s visiting your website. The more you know about your users, the more informed your design decisions can be.</p>\n<p>This data can form a useful starting point for many different types of research. One area where this data is particularly helpful is in recruiting people for usability tests. In usability testing, the better the participant matches the target persona, the better the test.</p>\n<p>Usability testing should show how “real” users interact with your website, and where they may be experiencing issues. Knowing who your users are will improve the results of your usability testing, and will give you a better chance of uncovering the issues your “real” users are encountering. </p>\n<p>The following section looks at the data in your analytics tool that will help build up your understanding of who your users are.</p>\n<h3 id=\"how-do-users-find-your-website-\">How Do Users Find Your Website?</h3>\n<p>Analyzing how users are finding your website can help you understand more about them, and about the context of their visit.</p>\n<p>Different analytics tools will classify “traffic sources” or “channels” in different ways. The following are some typical sources for your traffic:</p>\n<ul>\n<li><strong>Organic search</strong>. This typically identifies a user who has clicked an “unpaid” link from the search results.</li>\n<li><strong>Paid search</strong>. Paid search users, sometimes known as “Pay Per Click” or “PPC”, will have arrived on your website via a paid advert on a search engine.</li>\n<li><strong>Referral</strong>. Users from referral links will have followed a link from another website.</li>\n<li><strong>Social</strong>. Social media is often shown as a separate channel from other referral links.</li>\n<li><strong>Direct</strong>. This category includes users who type your domain into the address bar of their browser. It can also include users where the analytics package was unable to identify their traffic source.</li>\n<li><strong>Email</strong>. Links in emails will need to be tagged, since by default, analytics tools are unable to identify users clicking links that don’t appear on web pages.</li>\n</ul>\n<p>This analysis can give you a better idea about your users’ intentions. If you’re running a paid search campaign, for example, you’ll be able to see the keywords that were used to find your website (as long as you’ve linked up the Google Analytics and Adwords accounts, and enabled auto-tagging). If users are finding you based on “brand” search terms, you know they’re aware of your company and are searching for you specifically.</p>\n<p>Analyzing the behavioral metrics for users, broken down by channel, can help content and marketing teams make decisions about the amount of effort, resources, and budget to dedicate to specific channels. From a UX perspective, it can be useful for identifying problem areas (see Chapter 4), but it also helps to give insight into the mindset of your users. Knowing where your users are coming from can help you to identify whether they’re already familiar with your website, and can start to give you clues about the likely purpose of their visit.</p>\n<h3 id=\"where-do-your-users-come-from-\">Where Do Your Users Come From?</h3>\n<p>To begin with, it’s a good idea to start by finding out where—geographically speaking—your users come from. This is a very broad level of analysis that will help you focus your research. Looking at the location of your users will show you the role international visitors play in the success of your website. Geodata will also give you insight into the behavior of users on a national and regional level.</p>\n<p>Most analytics tools will give you location data for your users. In Google Analytics, this can be found in <strong>Audience > Geo > Location</strong>. This report will tell you where your users are coming from, and will also allow you to compare behavior metrics (and different dimensions) for users from different countries, regions or cities.</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508948203countryga.png\" alt=\"Location report in Google Analytics\" width=\"1045\" height=\"503\" class=\"aligncenter size-full wp-image-161116\" />\t\t\t</p>\n<p>Looking at the percentage of visitors from each country will help you understand the importance of international visitors to your website.</p>\n<p>But you need to be careful with your analysis here. Just because no one visits your site from Canada, for example, doesn’t necessarily mean that audience is not important to you. You could be accidentally blocking them! Your marketing efforts may not be reaching where they should, or there may be a whole host of other reasons for the lack of visits. Once again, remember that your website analytics tell you <em>what</em>, but not <em>why</em>.</p>\n<p>You may be assuming your website only attracts visitors from your own country, but this report may show that you should also consider the needs of international visitors. This could lead to practical considerations—such as the load speed of your website in other countries, international delivery rates for an ecommerce site, and possible cultural differences between other countries and your own.</p>\n<p>Cultural differences based on the country of your visitors can be considerations for both your website’s design and functionality. These differences can be hard to cater for, as cultural differences may be subtle, and often won’t lead to clear ideas for design changes. Still, detailed research on the cultural needs of you users is definitely recommended.</p>\n<p>On a more practical level, the way people use ecommerce websites varies dramatically depending on their country. According to <a href=\"https://alternativepayments.worldpay.com/territories/DE\">data from Worldpay</a>, only 12% of users in Germany make online purchases using cards.</p>\n<p>This compares with 63% of UK users and 72% of users in the USA. If you notice that your ecommerce website is getting a lot of visits from Germany, you’ll want to look at offering alternative payment methods. The most popular type of online payment in Germany in real-time bank transfer.</p>\n<p>Looking beyond the number of visits, you’ll be able to see behavioral metrics, such as time on site, bounce rate and conversion rate. Focusing on user behavior will enable you to pinpoint particular countries where there may be issues with your website, and thus opportunities to make improvements. If, for example, your ecommerce website is getting a lot of visits from a certain country, or countries, but the conversion rate is low, you may want to reassure those users that you deliver internationally.</p>\n<p>There could be many reasons why your conversion rate is low in a particular country. You may not ship to that country, your site may be in the wrong language, the products may be cheaper in that country, or you may not offer the right payment methods (as in the example of Germany). This is where it’s important not to jump to conclusions. Remember, the data only tells you <em>what</em> is happening. It’s important that you set aside research time to find out <em>why</em>.</p>\n<p>If you can see an opportunity to increase your conversion rate internationally, you might also want to consider personalizing your website in some way for those countries. This could be as simple as showing the flag of that country and being up front about the exact costs and delivery times for that location. This simple form of personalization will likely resonate with your international users, and will help you unlock potential additional revenue from international sales.</p>\n<p>If your analytics shows you’re getting a lot of visits from other countries, you’re likely to be missing out if you don’t factor in cultural differences!</p>\n<p>Geo reports can locate users down to state and city level. This means you may also want to assess your visitors by state, region and city to get a clearer picture of who your visitors are and how they behave. The importance of this level of detail will depend on the purpose of your website. For political websites, for example, localized data can be very important to see how a candidate is performing in a key state or region. </p>\n<h3 id=\"what-language-do-your-users-speak-\">What Language Do Your Users Speak?</h3>\n<p>Knowing what language your users speak can give you additional insight into the content you should serve up. Language and location are sometimes confused when looking at analytics, but the two dimensions have no direct connection. A user can be located in Paris but speak Spanish. Location is ascertained by the IP address of your user, while their language can be derived from the language settings of their browser.</p>\n<p>You may notice you’re getting a lot of visits from German-speaking users. If this is the case, you might want to look into creating a German version of your site if you don’t already have one.</p>\n<p>As with location, language can also give an indication of the culture of your users. The language used can also have a big impact on your design. Arabic text is displayed from right to left, and the Chinese alphabet contains thousands of characters. Both of these will potentially have a big impact on your page layouts.</p>\n<p>For example, websites targeted at Chinese audiences are likely to contain a lot of links, rather than offering users search options. This is due to Chinese keyboards being more difficult to use than western keyboards, because of the large number of characters in the Chinese alphabet.</p>\n<p>You may be surprised to learn about a larger than expected audience you had no idea existed. It’s likely that users who don’t share your language will be “silent”, and, as a result, may be overlooked and unrepresented when it comes to your user research. By “silent”, I mean these users are less likely to contact you or offer feedback than users who share your language.</p>\n<p>Finding out the languages used by your visitors is, of course, just a starting point. I wouldn’t recommend making any major changes based on this data alone. But it can play a very useful role in your user research process.</p>\n<h3 id=\"what-devices-and-browsers-are-they-using-\">What Devices and Browsers Are They Using?</h3>\n<p>When you know which devices are being used to visit your site, you get a clearer picture of the context in which users are viewing your website. Analyzing browser usage can also help you better understand your users.</p>\n<p>In user research, you should be careful not to rely on stereotypes or to make broad assumptions about your users. That said, knowing which browsers and devices they’re using can help you get a broad sense of their demographics.</p>\n<p>These kinds of studies may help you hypothesize why your users are behaving differently, but I certainly wouldn’t use them on their own. Find out more about your users to test these hypotheses.</p>\n<p>Device information is likely to tell you even more about your users. While you also need to be careful about assumptions, research shows, for example, that <a href=\"http://www.marketingcharts.com/online/the-demographics-of-us-smartphone-and-tablet-users-60669/\">adults in higher-income households are more than three times as likely as those in lower-income households to own a tablet</a>. There are also differences in the demographics of users of different device brands. A study has shown that <a href=\"http://www.forbes.com/sites/toddhixon/2014/04/10/what-kind-of-person-prefers-an-iphone/#6afb33213e5a\">iPhone users are better qualified and more affluent than Android users</a>.</p>\n<p>As with the previous example, there’s some value in these studies, but you need to be very careful how you apply it. Remember, the analytics data will tell you <em>what</em> is happening, but you’ll need to do further research to find out <em>why</em>.</p>\n<p>A common mistake analysts make with device reports is to assume that mobile users are “on the move” (such as commuting), while “desktops” are always used at home. <a href=\"https://www.thinkwithgoogle.com/research-studies/the-new-multi-screen-world-study.html\">A study by Google</a> showed over 60% of mobile usage is at home, while the “desktop” device category includes laptops, which people are likely to use while traveling.</p>\n<p>You need to be careful how you use device and browser data. Don’t make assumptions about your users based on the data alone, but instead let it help shape your research.</p>\n<p>Knowing the breakdown of browser and device types can also help identify who to recruit for user testing. If you know that 75% of your users are visiting your site on a mobile device, you’ll probably want to ensure the majority of your user testing takes place on mobile.</p>\n<h3 id=\"what-are-the-genders-and-ages-of-your-users-\">What are the Genders and Ages of Your Users?</h3>\n<p>Seeing how users from different demographic groups behave on a site can really help build up a picture of the different user types. In 2013, Google Analytics introduced demographic reports, which include information on users’ age, gender and interests. These reports are a potential gold mine for user research. It’s hard to tell exactly how accurate they really are, but the demographic data that Google Analytics reports is usually very similar to my own expectations for sites I know well. Google claims the reports 80–90% accurate, and <a href=\"http://www.humix.be/en/blog/web-analytics-en/how-accurate-are-google-analytics-demographics-reports/\">a study by Humix</a> concludes that the demographic data held by Google appears to be quite accurate.</p>\n<p>When I get a new analytics client, I often ask them about what they expect the breakdown of the age and gender of their users to be. I then compare this to the reports in Google Analytics—and they’re often very similar. While I’d wouldn’t recommend treating this data as if it’s 100% accurate, based on my experience I’d say you can be fairly confident it gives a good representation of the age and gender of your users. If possible, I also recommend testing this yourself, by surveying a sample of site users and correlating the results against the same user segment in Google Analytics.</p>\n<p>This information can be used to directly inform your personas, and to aid with your usability testing recruitment. You can also use this information to confirm, and fix, some concerns you may have about your audience.</p>\n<p>I’m one of the organizers of <a href=\"https://www.uxcampbrighton.org/\">UX Camp Brighton</a>, an annual UX “unconference” that takes place in my home town of Brighton in the UK. Recently, along with my fellow organizers, I had concerns about the gender balance of our attendees. As with most tech events, we were generally getting more male than female attendees, and we were keen to redress this balance. Checking the demographics report for our website confirmed that we did in fact have a far larger percentage of male visitors. Armed with this knowledge, we partnered with <a href=\"http://wespringforward.com/\">Spring Forward</a>, a series of events celebrating the role of women in digital culture. We both promoted each other’s events, and the result was a measurable increase in the percentage of women viewing our website.</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508948235genderGA.png\" alt=\"Changes to demographics over time\" width=\"600\" height=\"344\" class=\"aligncenter size-full wp-image-161118\" /></p>\n<p>We don’t collect gender data for ticket sales, so we can’t say for sure whether it changed the audience for the event, but it was certainly a step in the right direction, and is something we’ll look to do again next year.</p>\n<p>As well as age and gender, the demographics reports in Google Analytics give data on the interests of your users. Personally, I find these reports less useful than the other demographic reports. I often see the same, very generic interest groups appearing. Some of the categories are very broad, such as “movie lovers” and “TV lovers”, and probably apply to 90% of people in every community! </p>\n<h3 id=\"how-frequently-are-your-users-visiting-\">How Frequently Are Your Users Visiting?</h3>\n<p>Your analytics tool will be able to help you gauge the loyalty of your users. Users who keep returning to your site are likely to behave differently from first-time visitors. Grouping your users in this way can be helpful when you’re creating user types or personas.</p>\n<p>Below is a screenshot of a typical Frequency & Recency report from Google Analytics. This can be accessed by going to <strong>Audience > Behavior > Frequency & Recency</strong></p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508948269frequencyga.png\" alt=\"Frequency and Recency report\" width=\"825\" height=\"443\" class=\"aligncenter size-full wp-image-161119\" /></p>\n<p>We can see the majority of visitors only visited once during the selected time period of 30 days. At first glance, this suggests you only need to focus on that group. But if you add the users who visited more than once together, you’ll see they make up nearly 40% of the total.</p>\n<p>It can be helpful here to break these users down into groups that better meet your research requirements. You might want to group users as single visits, 2–10 visits, and 11+ visits. You can then label these groups as “one-off”, “repeat visitors” and “regular visitors”. This will give you a broad but useful overview of how often your users visit your site.</p>\n<h3 id=\"what-content-are-they-interested-in-\">What Content Are They Interested In?</h3>\n<p>In the previous chapter, we covered how to identify problem pages or areas on your website. The Pages report can also be useful for finding out what type of content your users are interested in.</p>\n<p>For example, if you’re looking at data for a real estate website, you may be able to group users into buyers, sellers, renters and letters, depending on the pages they’re viewing. This may not be an easy task, as users won’t always look just at pages targeted to them. In the real estate example, it’s likely people looking to sell their property will also look at properties already on sale to check prices. In this instance, you may need to choose pages further down the funnel to help group your users more accurately.</p>\n<p>This type of information will be useful for various aspects of your research, including creating personas.</p>\n","protected":false},"excerpt":{"rendered":"<p><em>The following is a short extract from our book, <a href=\"https://www.sitepoint.com/premium/books/researching-ux-analytics\">Researching UX: Analytics</a>, written by Luke Hay. It’s the ultimate guide to using analytics for improved user experience. SitePoint Premium members get access with their membership, or you can buy a copy in stores worldwide.</em></p>\n<p>To understand why your users behave the way they do, you first need to get to know them. You may make assumptions about who those users are, but you should be constantly challenging those assumptions, or at least be backing them up with facts.</p>\n<p>There’s a lot of data available in your analytics package that will help build up your knowledge of who’s visiting your website. The more you know about your users, the more informed your design decisions can be.</p>\n<p>This data can form a useful starting point for many different types of research. One area where this data is particularly helpful is in recruiting people for usability tests. In usability testing, the better the participant matches the target persona, the better the test.</p>\n<p>Usability testing should show how “real” users interact with your website, and where they may be experiencing issues. Knowing who your users are will improve the results of your usability testing, and will give you a better chance of uncovering the issues your “real” users are encountering. </p>\n<p>The following section looks at the data in your analytics tool that will help build up your understanding of who your users are.</p>\n<h3 id=\"how-do-users-find-your-website-\">How Do Users Find Your Website?</h3>\n<p>Analyzing how users are finding your website can help you understand more about them, and about the context of their visit.</p>\n<p>Different analytics tools will classify “traffic sources” or “channels” in different ways. The following are some typical sources for your traffic:</p>\n<ul>\n<li><strong>Organic search</strong>. This typically identifies a user who has clicked an “unpaid” link from the search results.</li>\n<li><strong>Paid search</strong>. Paid search users, sometimes known as “Pay Per Click” or “PPC”, will have arrived on your website via a paid advert on a search engine.</li>\n<li><strong>Referral</strong>. Users from referral links will have followed a link from another website.</li>\n<li><strong>Social</strong>. Social media is often shown as a separate channel from other referral links.</li>\n<li><strong>Direct</strong>. This category includes users who type your domain into the address bar of their browser. It can also include users where the analytics package was unable to identify their traffic source.</li>\n<li><strong>Email</strong>. Links in emails will need to be tagged, since by default, analytics tools are unable to identify users clicking links that don’t appear on web pages.</li>\n</ul>\n<p>This analysis can give you a better idea about your users’ intentions. If you’re running a paid search campaign, for example, you’ll be able to see the keywords that were used to find your website (as long as you’ve linked up the Google Analytics and Adwords accounts, and enabled auto-tagging). If users are finding you based on “brand” search terms, you know they’re aware of your company and are searching for you specifically.</p>\n<p>Analyzing the behavioral metrics for users, broken down by channel, can help content and marketing teams make decisions about the amount of effort, resources, and budget to dedicate to specific channels. From a UX perspective, it can be useful for identifying problem areas (see Chapter 4), but it also helps to give insight into the mindset of your users. Knowing where your users are coming from can help you to identify whether they’re already familiar with your website, and can start to give you clues about the likely purpose of their visit.</p>\n<h3 id=\"where-do-your-users-come-from-\">Where Do Your Users Come From?</h3>\n<p>To begin with, it’s a good idea to start by finding out where—geographically speaking—your users come from. This is a very broad level of analysis that will help you focus your research. Looking at the location of your users will show you the role international visitors play in the success of your website. Geodata will also give you insight into the behavior of users on a national and regional level.</p>\n<p>Most analytics tools will give you location data for your users. In Google Analytics, this can be found in <strong>Audience > Geo > Location</strong>. This report will tell you where your users are coming from, and will also allow you to compare behavior metrics (and different dimensions) for users from different countries, regions or cities.</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508948203countryga.png\" alt=\"Location report in Google Analytics\" width=\"1045\" height=\"503\" class=\"aligncenter size-full wp-image-161116\" />\t\t\t</p>\n<p>Looking at the percentage of visitors from each country will help you understand the importance of international visitors to your website.</p>\n<p>But you need to be careful with your analysis here. Just because no one visits your site from Canada, for example, doesn’t necessarily mean that audience is not important to you. You could be accidentally blocking them! Your marketing efforts may not be reaching where they should, or there may be a whole host of other reasons for the lack of visits. Once again, remember that your website analytics tell you <em>what</em>, but not <em>why</em>.</p>\n<p>You may be assuming your website only attracts visitors from your own country, but this report may show that you should also consider the needs of international visitors. This could lead to practical considerations—such as the load speed of your website in other countries, international delivery rates for an ecommerce site, and possible cultural differences between other countries and your own.</p>\n<p>Cultural differences based on the country of your visitors can be considerations for both your website’s design and functionality. These differences can be hard to cater for, as cultural differences may be subtle, and often won’t lead to clear ideas for design changes. Still, detailed research on the cultural needs of you users is definitely recommended.</p>\n<p>On a more practical level, the way people use ecommerce websites varies dramatically depending on their country. According to <a href=\"https://alternativepayments.worldpay.com/territories/DE\">data from Worldpay</a>, only 12% of users in Germany make online purchases using cards.</p>\n<p>This compares with 63% of UK users and 72% of users in the USA. If you notice that your ecommerce website is getting a lot of visits from Germany, you’ll want to look at offering alternative payment methods. The most popular type of online payment in Germany in real-time bank transfer.</p>\n<p>Looking beyond the number of visits, you’ll be able to see behavioral metrics, such as time on site, bounce rate and conversion rate. Focusing on user behavior will enable you to pinpoint particular countries where there may be issues with your website, and thus opportunities to make improvements. If, for example, your ecommerce website is getting a lot of visits from a certain country, or countries, but the conversion rate is low, you may want to reassure those users that you deliver internationally.</p>\n<p>There could be many reasons why your conversion rate is low in a particular country. You may not ship to that country, your site may be in the wrong language, the products may be cheaper in that country, or you may not offer the right payment methods (as in the example of Germany). This is where it’s important not to jump to conclusions. Remember, the data only tells you <em>what</em> is happening. It’s important that you set aside research time to find out <em>why</em>.</p>\n<p>If you can see an opportunity to increase your conversion rate internationally, you might also want to consider personalizing your website in some way for those countries. This could be as simple as showing the flag of that country and being up front about the exact costs and delivery times for that location. This simple form of personalization will likely resonate with your international users, and will help you unlock potential additional revenue from international sales.</p>\n<p>If your analytics shows you’re getting a lot of visits from other countries, you’re likely to be missing out if you don’t factor in cultural differences!</p>\n<p>Geo reports can locate users down to state and city level. This means you may also want to assess your visitors by state, region and city to get a clearer picture of who your visitors are and how they behave. The importance of this level of detail will depend on the purpose of your website. For political websites, for example, localized data can be very important to see how a candidate is performing in a key state or region. </p>\n<h3 id=\"what-language-do-your-users-speak-\">What Language Do Your Users Speak?</h3>\n<p>Knowing what language your users speak can give you additional insight into the content you should serve up. Language and location are sometimes confused when looking at analytics, but the two dimensions have no direct connection. A user can be located in Paris but speak Spanish. Location is ascertained by the IP address of your user, while their language can be derived from the language settings of their browser.</p>\n","protected":false},"author":72443,"featured_media":161158,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[6131,425,412],"tags":[904,10250,11007,1097],"_links":{"self":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/posts/161113"}],"collection":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/posts"}],"about":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/types/post"}],"author":[{"embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/users/72443"}],"replies":[{"embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/comments?post=161113"}],"version-history":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/posts/161113/revisions"}],"wp_featuredmedia":[{"embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/media/161158"}],"wp_attachment":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/media?parent=161113"}],"wp_term":[{"taxonomy":"category","embeddable":false,"href":"https://www.sitepoint.com/wp-json/wp/v2/categories?post=161113"},{"taxonomy":"post_tag","embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/tags?post=161113"}],"curies":[{"name":"wp","href":"https://api.w.org/{rel}","templated":true}]}}
{"index":{"_index":"blogs","_id":161109,"_type":"default"}}
{"id":161109,"date":"2017-10-31T10:00:12","date_gmt":"2017-10-31T17:00:12","guid":{"rendered":"https://www.sitepoint.com/?p=161109"},"modified":"2017-10-26T20:47:31","modified_gmt":"2017-10-27T03:47:31","slug":"first-php-code","status":"publish","type":"post","link":"https://www.sitepoint.com/first-php-code/","title":{"rendered":"Your First PHP Code"},"content":{"rendered":"<p><em>The following is a short extract from our new book, <a href=\"https://www.sitepoint.com/premium/books/php-mysql-novice-to-ninja-6th-edition\">PHP & MySQL: Novice to Ninja, 6th Edition</a>, written by Tom Butler and Kevin Yank. It’s the ultimate beginner’s guide to PHP. SitePoint Premium members get access with their membership, or you can buy a copy in stores worldwide.</em></p>\n<p>Now that you have your virtual server up and running, it’s time to write your first PHP script. PHP is a server-side language. This concept may be a little difficult to grasp, especially if you’ve only ever designed websites using client-side languages like HTML, CSS, and JavaScript.</p>\n<p>A server-side language is similar to JavaScript in that it allows you to embed little programs (scripts) into the HTML code of a web page. When executed, these programs give you greater control over what appears in the browser window than HTML alone can provide. The key difference between JavaScript and PHP is the stage of loading the web page at which these embedded programs are executed.</p>\n<p>Client-side languages like JavaScript are read and executed by the web browser after downloading the web page (embedded programs and all) from the web server. In contrast, server-side languages like PHP are run by the web <em>server</em>, before sending the web page to the browser. Whereas client-side languages give you control over how a page behaves once it’s displayed by the browser, server-side languages let you generate customized pages on the fly before they’re even sent to the browser.</p>\n<p>Once the web server has executed the PHP code embedded in a web page, the result takes the place of the PHP code in the page. All the browser sees is standard HTML code when it receives the page, hence the name “server-side language.” Let’s look at simple example of some PHP that generates a random number between 1 and 10 and then displays it on the screen: </p>\n<pre><code class=\"php language-php\">\r\n<!DOCTYPE html>\r\n<html lang="en">\r\n <head>\r\n <meta charset="utf-8">\r\n <title>Random Number</title>\r\n </head>\r\n <body>\r\n <p>Generating a random number between 1 and 10:\r\n <?php\r\n\r\n echo rand(1, 10);\r\n\r\n ?>\r\n </p>\r\n </body>\r\n</html>\r\n </code></pre>\n<p>Most of this is plain HTML. Only the line between <code><?php</code> and <code>?></code> is PHP code. <code><?php</code> marks the start of an embedded PHP script and <code>?></code> marks its end. The web server is asked to interpret everything between these two delimiters and convert it to regular HTML code before it sends the web page to the requesting browser. If you right-click inside your browser and choose <strong>View Source</strong> (the text may be different depending on the browser you’re using) you can see that the browser is presented with the following:</p>\n<pre><code class=\"html language-html\">\r\n<!DOCTYPE html>\r\n<html lang="en">\r\n <head>\r\n <meta charset="utf-8">\r\n <title>Random Number</title>\r\n </head>\r\n <body>\r\n <p>Generating a random number between 1 and 10:\r\n 5\r\n </p>\r\n </body>\r\n</html>\r\n </code></pre>\n<p>Notice that all signs of the PHP code have disappeared. In its place the output of the script has appeared, and it looks just like standard HTML. This example demonstrates several advantages of server-side scripting …</p>\n<ul>\n<li><strong>No browser compatibility issues</strong>. PHP scripts are interpreted by the web server alone, so there’s no need to worry about whether the language features you’re using are supported by the visitor’s browser.</li>\n<li><strong>Access to server-side resources</strong>. In the example above, we placed a random number generated by the web server into the web page. If we had inserted the number using JavaScript, the number would be generated in the browser and someone could potentially amend the code to insert a specific number. Granted, there are more impressive examples of the exploitation of server-side resources, such as inserting content pulled out of a MySQL database.</li>\n<li><strong>Reduced load on the client</strong>. JavaScript can delay the display of a web page significantly (especially on mobile devices!) as the browser must run the script before it can display the web page. With server-side code, this burden is passed to the web server, which you can make as beefy as your application requires (and your wallet can afford).</li>\n<li><strong>Choice</strong>. When writing code that’s run in the browser, the browser has to understand how to run the code given to it. All modern browsers understand HTML, CSS and JavaScript. To write some code that’s run in the browser, you must use one of these languages. By running code on the server that generates HTML, you have a choice of many languages—one of which is PHP.</li>\n</ul>\n<h2 id=\"basic-syntax-and-statements\">Basic Syntax and Statements</h2>\n<p>PHP syntax will be very familiar to anyone with an understanding of JavaScript, C, C++, C#, Objective-C, Java, Perl, or any other C-derived language. But if these languages are unfamiliar to you, or if you’re new to programming in general, there’s no need to worry about it.</p>\n<p>A PHP script consists of a series of <strong>commands</strong>, or statements. Each statement is an instruction that must be followed by the web server before it can proceed to the next instruction. PHP statements, like those in the aforementioned languages, are always terminated by a semicolon (<code>;</code>).</p>\n<p>This is a typical PHP statement:</p>\n<pre><code class=\"php language-php\">echo 'This is a <strong>test</strong>!';\r\n </code></pre>\n<p>This is an <code>echo</code> statement, which is used to generate content (usually HTML code) to send to the browser. An <code>echo</code> statement simply takes the text it’s given and inserts it into the page’s HTML code at the position of the PHP script where it was contained.</p>\n<p>In this case, we’ve supplied a string of text to be output: <code>This is a <strong>test</strong>!</code>. Notice that the string of text contains HTML tags (<code><strong></code> and <code></strong></code>), which is perfectly acceptable.</p>\n<p>So, if we take this statement and put it into a complete web page, here’s the resulting code:</p>\n<pre><code class=\"php language-php\"><!DOCTYPE html>\r\n<html lang="en">\r\n <head>\r\n <meta charset="utf-8">\r\n <title>Test page</title>\r\n </head>\r\n <body>\r\n <p><?php echo 'This is a <strong>test</strong>!'; ?></p>\r\n </body>\r\n</html>\r\n </code></pre>\n<p>If you place this file on your web server and then request it using a web browser, your browser will receive this HTML code:</p>\n<pre><code class=\"html language-html\"><!DOCTYPE html>\r\n<html lang="en">\r\n <head>\r\n <meta charset="utf-8">\r\n <title>Test page</title>\r\n </head>\r\n <body>\r\n <p>This is a <strong>test</strong>!</p>\r\n </body>\r\n</html>\r\n </code></pre>\n<p>The <code>random.php</code> example we looked at earlier contained a slightly more complex <code>echo</code> statement:</p>\n<pre><code class=\"php language-php\">\r\necho rand(1, 10);\r\n </code></pre>\n<p>You’ll notice that, in the first example, PHP is given some text to print directly, and in the second, PHP is given an instruction to follow. PHP tries to read anything that exists outside quotes as an instruction it must follow. Anything inside quotes is treated as a <strong>string</strong>, which means PHP doesn’t process it at all but just passes it to the command you called. So the following code will pass the string <code>This is a <strong>test</strong>!</code> directly to the <code>echo</code> command:</p>\n<pre><code class=\"php language-php\">\r\necho 'This is a <strong>test</strong>!';\r\n </code></pre>\n<p>A string is signified using a start quote and an end quote. PHP will see the first <code>'</code> as the start of the string and find the next <code>'</code> and use that as the end of the string.</p>\n<p>In contrast, the following code will first run the built-in function <code>rand</code> to generate a random number and then pass the result to the echo command:</p>\n<pre><code class=\"php language-php\">\r\necho rand(1, 10);\r\n </code></pre>\n<p>You can think of built-in functions as tasks that PHP knows how to do without you needing to spell out the details. PHP has many built-in functions that let you do everything, from sending email to working with information stored in various types of databases.</p>\n<p>PHP won’t try to run anything that’s inside a string. The following code won’t have the result you may be expecting:</p>\n<pre><code class=\"php language-php\">\r\necho 'rand(1, 10)';\r\n </code></pre>\n<p>Instead of running the inbuilt function <code>rand</code>, PHP will see it as a string, and rather than printing out a random number, it will actually send the text <code>rand(1, 10)</code> to the browser, which probably isn’t what you wanted to do. It’s important to understand the difference between a string and <em>code</em>. PHP will see any text outside quotes as a series of commands it should follow. Anything inside quotes is a string and is <em>data</em> that PHP will work with.</p>\n<p>PHP doesn’t try to understand strings. They can contain any characters in any order. But code—which is essentially a series of <em>instructions</em>—must follow a rigid structure for a computer to understand it.</p>\n<p>When you <strong>invoke</strong> a function in PHP—that is, ask it to do its job—you’re said to be <strong>calling</strong> that function. Most functions return a value when they’re called; PHP then behaves as if you’d actually just typed that returned value in your code instead. In the <code>echo 'rand(1, 10)';</code> example, our <code>echo</code> statement contains a call to the <code>rand</code> function, which returns a random number as a string of text. The <code>echo</code> statement then outputs the value returned by the function call.</p>\n<p>Every function in PHP can have one or more <strong>arguments</strong> that allow you to make the function behave in a slightly different way. The <code>rand</code> function takes two arguments: the minimum random number and the maximum. By changing the values that are passed to the function, you’re able to change the way it works. For example, if you wanted a random number between 1 and 50, you could use the code:</p>\n<pre><code class=\"php language-php\">\r\necho rand(1, 50);\r\n </code></pre>\n<p>You may wonder why we need to surround the arguments with parentheses (<code>(1, 50)</code>). The parentheses serve two purposes. First, they indicate that <code>rand</code> is a function that you want to call. Second, they mark the beginning and end of a list of arguments—PHP statements that you wish to provide—in order to tell the function what you want it to do. In the case of the <code>rand</code> function, you need to provide a minimum and a maximum value. Those values are separated by a comma.</p>\n<p>Later on, we’ll look at functions that take different kinds of arguments. We’ll also consider functions that take no arguments at all. These functions will still need the parentheses, even though there will be nothing to type between them.</p>\n","protected":false},"excerpt":{"rendered":"<p><em>The following is a short extract from our new book, <a href=\"https://www.sitepoint.com/premium/books/php-mysql-novice-to-ninja-6th-edition\">PHP & MySQL: Novice to Ninja, 6th Edition</a>, written by Tom Butler and Kevin Yank. It’s the ultimate beginner’s guide to PHP. SitePoint Premium members get access with their membership, or you can buy a copy in stores worldwide.</em></p>\n<p>Now that you have your virtual server up and running, it’s time to write your first PHP script. PHP is a server-side language. This concept may be a little difficult to grasp, especially if you’ve only ever designed websites using client-side languages like HTML, CSS, and JavaScript.</p>\n<p>A server-side language is similar to JavaScript in that it allows you to embed little programs (scripts) into the HTML code of a web page. When executed, these programs give you greater control over what appears in the browser window than HTML alone can provide. The key difference between JavaScript and PHP is the stage of loading the web page at which these embedded programs are executed.</p>\n<p>Client-side languages like JavaScript are read and executed by the web browser after downloading the web page (embedded programs and all) from the web server. In contrast, server-side languages like PHP are run by the web <em>server</em>, before sending the web page to the browser. Whereas client-side languages give you control over how a page behaves once it’s displayed by the browser, server-side languages let you generate customized pages on the fly before they’re even sent to the browser.</p>\n<p>Once the web server has executed the PHP code embedded in a web page, the result takes the place of the PHP code in the page. All the browser sees is standard HTML code when it receives the page, hence the name “server-side language.” Let’s look at simple example of some PHP that generates a random number between 1 and 10 and then displays it on the screen: </p>\n<pre><code class=\"php language-php\">\r\n<!DOCTYPE html>\r\n<html lang="en">\r\n <head>\r\n <meta charset="utf-8">\r\n <title>Random Number</title>\r\n </head>\r\n <body>\r\n <p>Generating a random number between 1 and 10:\r\n <?php\r\n\r\n echo rand(1, 10);\r\n\r\n ?>\r\n </p>\r\n </body>\r\n</html>\r\n </code></pre>\n<p>Most of this is plain HTML. Only the line between <code><?php</code> and <code>?></code> is PHP code. <code><?php</code> marks the start of an embedded PHP script and <code>?></code> marks its end. The web server is asked to interpret everything between these two delimiters and convert it to regular HTML code before it sends the web page to the requesting browser. If you right-click inside your browser and choose <strong>View Source</strong> (the text may be different depending on the browser you’re using) you can see that the browser is presented with the following:</p>\n<pre><code class=\"html language-html\">\r\n<!DOCTYPE html>\r\n<html lang="en">\r\n <head>\r\n <meta charset="utf-8">\r\n <title>Random Number</title>\r\n </head>\r\n <body>\r\n <p>Generating a random number between 1 and 10:\r\n 5\r\n </p>\r\n </body>\r\n</html>\r\n </code></pre>\n<p>Notice that all signs of the PHP code have disappeared. In its place the output of the script has appeared, and it looks just like standard HTML. This example demonstrates several advantages of server-side scripting …</p>\n<ul>\n<li><strong>No browser compatibility issues</strong>. PHP scripts are interpreted by the web server alone, so there’s no need to worry about whether the language features you’re using are supported by the visitor’s browser.</li>\n<li><strong>Access to server-side resources</strong>. In the example above, we placed a random number generated by the web server into the web page. If we had inserted the number using JavaScript, the number would be generated in the browser and someone could potentially amend the code to insert a specific number. Granted, there are more impressive examples of the exploitation of server-side resources, such as inserting content pulled out of a MySQL database.</li>\n<li><strong>Reduced load on the client</strong>. JavaScript can delay the display of a web page significantly (especially on mobile devices!) as the browser must run the script before it can display the web page. With server-side code, this burden is passed to the web server, which you can make as beefy as your application requires (and your wallet can afford).</li>\n<li><strong>Choice</strong>. When writing code that’s run in the browser, the browser has to understand how to run the code given to it. All modern browsers understand HTML, CSS and JavaScript. To write some code that’s run in the browser, you must use one of these languages. By running code on the server that generates HTML, you have a choice of many languages—one of which is PHP.</li>\n</ul>\n<h2 id=\"basic-syntax-and-statements\">Basic Syntax and Statements</h2>\n<p>PHP syntax will be very familiar to anyone with an understanding of JavaScript, C, C++, C#, Objective-C, Java, Perl, or any other C-derived language. But if these languages are unfamiliar to you, or if you’re new to programming in general, there’s no need to worry about it.</p>\n","protected":false},"author":71833,"featured_media":161155,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[37],"tags":[9760],"_links":{"self":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/posts/161109"}],"collection":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/posts"}],"about":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/types/post"}],"author":[{"embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/users/71833"}],"replies":[{"embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/comments?post=161109"}],"version-history":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/posts/161109/revisions"}],"wp_featuredmedia":[{"embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/media/161155"}],"wp_attachment":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/media?parent=161109"}],"wp_term":[{"taxonomy":"category","embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/categories?post=161109"},{"taxonomy":"post_tag","embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/tags?post=161109"}],"curies":[{"name":"wp","href":"https://api.w.org/{rel}","templated":true}]}}
{"index":{"_index":"blogs","_id":161052,"_type":"default"}}
{"id":161052,"date":"2017-10-30T10:00:50","date_gmt":"2017-10-30T17:00:50","guid":{"rendered":"https://www.sitepoint.com/?p=161052"},"modified":"2017-10-26T20:44:16","modified_gmt":"2017-10-27T03:44:16","slug":"designing-form-layout-spacing","status":"publish","type":"post","link":"https://www.sitepoint.com/designing-form-layout-spacing/","title":{"rendered":"Designing Form Layout: Spacing"},"content":{"rendered":"<p><em>The following is a short extract from our book, <a href=\"https://www.sitepoint.com/premium/books/designing-ux-forms\">Designing UX: Forms</a>, written by Jessica Enders. It’s the ultimate guide to form design, a key part of effective UX design. SitePoint Premium members get access with their membership, or you can buy a copy in stores worldwide.</em></p>\n<p class=\"calibre2\">We can subtly communicate with the user through a few tweaks of spacing.</p>\n<h3 class=\"calibre7\" id=\"proximity\">Proximity</h3>\n<p class=\"calibre2\">Human beings see things that are close to each other as being related. Conversely, things that are not related usually have some space between them.</p>\n<p class=\"calibre2\">These principles tell us to put the parts of a question—label, question-level help and answer fields—close together. Our form is pretty good for this so far, but let’s just move the labels a bit to the right, so they’re closer to their fields:</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508852510BankExample11.png\" alt=\"Flush right labels should be close to their fields\" width=\"998\" height=\"982\" class=\"aligncenter size-full wp-image-161053\" /></p>\n<p class=\"figcaption\">Flush right labels should be close to their fields.</p>\n<p class=\"calibre17\">On the other hand, there needs to be some distance between each question:</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508852550BankExample12.png\" alt=\"Questions should be far enough apart that it’s clear where one ends and the next one starts\" width=\"998\" height=\"1046\" class=\"aligncenter size-full wp-image-161054\" /></p>\n<p class=\"figcaption\">Questions should be far enough apart that it’s clear where one ends and the next one starts.</p>\n<p class=\"calibre17\">Remember how the focus of a user’s vision is about nine characters wide? Well, this means question-level help that’s on the right side of a field often won’t be seen:</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508852589QuestionLevelHelpOnRight.png\" alt=\"Their focus on fields means many users won’t even see the question-level help in this form\" width=\"447\" height=\"136\" class=\"aligncenter size-full wp-image-161055\" /></p>\n<p class=\"figcaption\">Their focus on fields means many users won’t even see the question-level help in this form.</p>\n<p class=\"calibre2\">We could move the question-level help underneath the field, but that means users might not see it until after they’ve answered. It’s also less accessible.</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508852618QuestionLevelHelpBelow.png\" alt=\"Question-level help below the field is not especially usable or accessible\" width=\"334\" height=\"125\" class=\"aligncenter size-full wp-image-161056\" /></p>\n<p class=\"figcaption\">Question-level help below the field is not especially usable or accessible.</p>\n<p class=\"calibre17\">The best place for question-level help is <em>between</em> the label and the field (as shown in the image below). Formatting instructions—like the DD MM YYYY on date of birth—should go above the field:</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508852658BankExample13.png\" alt=\"Formatting instructions positioned above the field\" width=\"998\" height=\"1078\" class=\"aligncenter size-full wp-image-161057\" /><br />\n<img alt=\"\" src=\"../Images/bankexample13.png\"/></p>\n<p class=\"figcaption\">Formatting instructions positioned above the field</p>\n<p class=\"calibre17\">Other question-level help should go below the label. See the ABN, employee and marketing questions for examples of this:</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508853074BankExample14.png\" alt=\"Other question-level help positioned below the label.\" width=\"998\" height=\"1136\" class=\"aligncenter size-full wp-image-161059\" /></p>\n<p class=\"figcaption\">Other question-level help positioned below the label.</p>\n<p class=\"calibre2\">Finally, when we use checkboxes and radio buttons, we need to make sure the labels are close to the right button or box. If they’re too far away, things get confusing, particularly if you aren’t shading the touch area:</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508853184LabelsTooFarAway.png\" alt=\"The distance between the labels “Yes” and “No” and their respective radio buttons means the user has to stop and think\" width=\"500\" height=\"74\" class=\"aligncenter size-full wp-image-161061\" /></p>\n<p class=\"figcaption\">The distance between the labels “Yes” and “No” and their respective radio buttons means the user has to stop and think.</p>\n<p class=\"calibre2\">Here’s an even more extreme illustration of poorly spaced labels on radio buttons:</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508853232LabelSpacingPoor.png\" alt=\"It’s likely that many users will give an unintended rating, given the poor spacing here\" width=\"591\" height=\"53\" class=\"aligncenter size-full wp-image-161062\" /></p>\n<p class=\"figcaption\">It’s likely that many users will give an unintended rating, given the poor spacing here.</p>\n<h3 class=\"calibre7\" id=\"text-box-widths\">Text Box Widths</h3>\n<p class=\"calibre2\">While we’re adjusting spacing, let’s fix up our text box widths.</p>\n<p class=\"calibre17\">At the moment, aside from the text boxes for date of birth, all our text boxes are the same width:</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508853264BankExample15.png\" alt=\"Text boxes all the same width\" width=\"1003\" height=\"1136\" class=\"aligncenter size-full wp-image-161063\" /></p>\n<p class=\"calibre17\">However, the width of a text box tells the user what sort of information is needed. The user experience will be better if we make the sizes proportional to the expected information (as we have, in fact, already done with date of birth):</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508853292BankExample16.png\" alt=\"Text boxes adjusted to have width proportional to typical answers\" width=\"998\" height=\"1136\" class=\"aligncenter size-full wp-image-161064\" /></p>\n<p class=\"calibre2\">Note we’re talking about <em>visual</em> width here, not acceptable number of characters. The email address field may have a visual width as shown, but should still accept up to 256 characters.</p>\n<h3 class=\"calibre7\" id=\"empty-text-boxes\">Empty Text Boxes</h3>\n<p class=\"calibre2\">Another important aspect of text box spacing is the space they have <em>inside</em>. This empty space is how users know they need to type something in there.</p>\n<p class=\"calibre2\">Way too many forms have text boxes that <em>aren’t</em> empty. The two main culprits are:</p>\n<ol>\n<li class=\"calibre3\">background color</li>\n<li class=\"calibre3\">placeholder text.</li>\n</ol>\n<h4 class=\"calibre8\" id=\"no-background-color\">No Background Color</h4>\n<p class=\"calibre2\"><strong class=\"calibre4\">Do not give your fields a background color</strong>. Background color in fields makes them look like buttons (just as buttons without background color look like fields):</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508853382BackgroundFields1.png\" alt=\"On this form, background color makes fields look like buttons, and vice versa\" width=\"180\" height=\"274\" class=\"aligncenter size-full wp-image-161065\" /></p>\n<p class=\"figcaption\">On this form, background color makes fields look like buttons, and vice versa.</p>\n<p class=\"calibre2\">A simple border on four sides is enough to show users where to type:</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508853413BackgroundFields2.png\" alt=\"You don’t need much to show users where their answers go\" width=\"265\" height=\"291\" class=\"aligncenter size-full wp-image-161066\" /></p>\n<p class=\"figcaption\">You don’t need much to show users where their answers go.</p>\n<p class=\"calibre2\">Just make sure your border can be seen:</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508854149BackgroundFields3.png\" alt=\"The field borders on this form are so light they’re nearly impossible to see\" width=\"325\" height=\"355\" class=\"aligncenter size-full wp-image-161067\" /></p>\n<p class=\"figcaption\">The field borders on this form are so light they’re nearly impossible to see.</p>\n<h4 class=\"calibre8\" id=\"no-placeholder-text\">No Placeholder Text</h4>\n<p class=\"calibre2\">Even worse than a background color is putting text inside the field. <strong class=\"calibre4\">The only text that should appear inside a field is the user’s answer!</strong></p>\n<p class=\"calibre2\">Such text, also known as <strong class=\"calibre4\">placeholder text</strong>, is unfortunately far too common. Sometimes it’s the field label:</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508854887PlaceholderText1.png\" alt=\"/>This form’s labels appear inside fields” width=”300″ height=”185″ class=”aligncenter size-full wp-image-161068″ /></p>\n<p class=\"figcaption\">This form’s labels appear inside fields.</p>\n<p class=\"calibre2\">Sometimes it’s question-level help:</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508854914PlaceholderText2.png\" alt=\"question-level help shown inside fields\" width=\"316\" height=\"63\" class=\"aligncenter size-full wp-image-161069\" /></p>\n<p class=\"figcaption\">Question-level help shown inside fields.</p>\n<p class=\"calibre17\">Sometimes it’s just downright useless:</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508854942PlaceholderText3.png\" alt=\"Pointless information inside fields\" width=\"300\" height=\"376\" class=\"aligncenter size-full wp-image-161070\" /></p>\n<p class=\"figcaption\">Pointless information inside fields.</p>\n<p class=\"calibre2\">It’s so important not to do this, I’m going to say it again. <strong class=\"calibre4\">Never include text inside your fields</strong>. It dramatically worsens the form filling experience, as many users will:</p>\n<ul class=\"credits\">\n<li class=\"calibre3\">think the question has already been answered, triggering errors</li>\n<li class=\"calibre3\">leave the placeholder text there, messing up your data</li>\n<li class=\"calibre3\">not see the placeholder text before it disappears (especially if they watch the keyboard when typing)</li>\n<li class=\"calibre3\">not be able to see all of the placeholder text, because it’s limited by the visible width of the field</li>\n<li class=\"calibre3\">forget what the label said</li>\n<li class=\"calibre3\">forget what the question-level help said</li>\n<li class=\"calibre3\">find the text too small to read</li>\n<li class=\"calibre3\">be unable to review their answers</li>\n<li class=\"calibre3\">have greater trouble correcting errors.</li>\n</ul>\n<p class=\"calibre2\">Furthermore, text inside fields is often <a href=\"http://output.jsbin.com/vonesu/10/\">not accessible</a>, and <a href=\"http://caniuse.com/#feat=input-placeholder\">the placeholder attribute is not accurately supported in all browsers</a>. (It was once the case that placeholder text was <em>needed</em> for accessibility, because screen readers didn’t always announce the form field. Now screen readers consistently use <a href=\"https://www.w3.org/TR/html5/forms.html#the-label-element\">the <code class=\"calibre16\">label</code> element</a> to indicate the purpose of a field.)</p>\n<p class=\"calibre2\">“But it saves space!” some designers will protest. That’s true. But that space is saved <strong class=\"calibre4\">at the expense of being able to actually fill out the form</strong>. Don’t do it. Just put your text outside your fields.</p>\n","protected":false},"excerpt":{"rendered":"<p><em>The following is a short extract from our book, <a href=\"https://www.sitepoint.com/premium/books/designing-ux-forms\">Designing UX: Forms</a>, written by Jessica Enders. It’s the ultimate guide to form design, a key part of effective UX design. SitePoint Premium members get access with their membership, or you can buy a copy in stores worldwide.</em></p>\n<p class=\"calibre2\">We can subtly communicate with the user through a few tweaks of spacing.</p>\n<h3 class=\"calibre7\" id=\"proximity\">Proximity</h3>\n<p class=\"calibre2\">Human beings see things that are close to each other as being related. Conversely, things that are not related usually have some space between them.</p>\n<p class=\"calibre2\">These principles tell us to put the parts of a question—label, question-level help and answer fields—close together. Our form is pretty good for this so far, but let’s just move the labels a bit to the right, so they’re closer to their fields:</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508852510BankExample11.png\" alt=\"Flush right labels should be close to their fields\" width=\"998\" height=\"982\" class=\"aligncenter size-full wp-image-161053\" /></p>\n<p class=\"figcaption\">Flush right labels should be close to their fields.</p>\n<p class=\"calibre17\">On the other hand, there needs to be some distance between each question:</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508852550BankExample12.png\" alt=\"Questions should be far enough apart that it’s clear where one ends and the next one starts\" width=\"998\" height=\"1046\" class=\"aligncenter size-full wp-image-161054\" /></p>\n<p class=\"figcaption\">Questions should be far enough apart that it’s clear where one ends and the next one starts.</p>\n<p class=\"calibre17\">Remember how the focus of a user’s vision is about nine characters wide? Well, this means question-level help that’s on the right side of a field often won’t be seen:</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508852589QuestionLevelHelpOnRight.png\" alt=\"Their focus on fields means many users won’t even see the question-level help in this form\" width=\"447\" height=\"136\" class=\"aligncenter size-full wp-image-161055\" /></p>\n<p class=\"figcaption\">Their focus on fields means many users won’t even see the question-level help in this form.</p>\n<p class=\"calibre2\">We could move the question-level help underneath the field, but that means users might not see it until after they’ve answered. It’s also less accessible.</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508852618QuestionLevelHelpBelow.png\" alt=\"Question-level help below the field is not especially usable or accessible\" width=\"334\" height=\"125\" class=\"aligncenter size-full wp-image-161056\" /></p>\n<p class=\"figcaption\">Question-level help below the field is not especially usable or accessible.</p>\n<p class=\"calibre17\">The best place for question-level help is <em>between</em> the label and the field (as shown in the image below). Formatting instructions—like the DD MM YYYY on date of birth—should go above the field:</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508852658BankExample13.png\" alt=\"Formatting instructions positioned above the field\" width=\"998\" height=\"1078\" class=\"aligncenter size-full wp-image-161057\" /><br />\n<img alt=\"\" src=\"../Images/bankexample13.png\"/></p>\n<p class=\"figcaption\">Formatting instructions positioned above the field</p>\n<p class=\"calibre17\">Other question-level help should go below the label. See the ABN, employee and marketing questions for examples of this:</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508853074BankExample14.png\" alt=\"Other question-level help positioned below the label.\" width=\"998\" height=\"1136\" class=\"aligncenter size-full wp-image-161059\" /></p>\n<p class=\"figcaption\">Other question-level help positioned below the label.</p>\n<p class=\"calibre2\">Finally, when we use checkboxes and radio buttons, we need to make sure the labels are close to the right button or box. If they’re too far away, things get confusing, particularly if you aren’t shading the touch area:</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508853184LabelsTooFarAway.png\" alt=\"The distance between the labels “Yes” and “No” and their respective radio buttons means the user has to stop and think\" width=\"500\" height=\"74\" class=\"aligncenter size-full wp-image-161061\" /></p>\n<p class=\"figcaption\">The distance between the labels “Yes” and “No” and their respective radio buttons means the user has to stop and think.</p>\n<p class=\"calibre2\">Here’s an even more extreme illustration of poorly spaced labels on radio buttons:</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508853232LabelSpacingPoor.png\" alt=\"It’s likely that many users will give an unintended rating, given the poor spacing here\" width=\"591\" height=\"53\" class=\"aligncenter size-full wp-image-161062\" /></p>\n<p class=\"figcaption\">It’s likely that many users will give an unintended rating, given the poor spacing here.</p>\n<h3 class=\"calibre7\" id=\"text-box-widths\">Text Box Widths</h3>\n<p class=\"calibre2\">While we’re adjusting spacing, let’s fix up our text box widths.</p>\n<p class=\"calibre17\">At the moment, aside from the text boxes for date of birth, all our text boxes are the same width:</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508853264BankExample15.png\" alt=\"Text boxes all the same width\" width=\"1003\" height=\"1136\" class=\"aligncenter size-full wp-image-161063\" /></p>\n<p class=\"calibre17\">However, the width of a text box tells the user what sort of information is needed. The user experience will be better if we make the sizes proportional to the expected information (as we have, in fact, already done with date of birth):</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508853292BankExample16.png\" alt=\"Text boxes adjusted to have width proportional to typical answers\" width=\"998\" height=\"1136\" class=\"aligncenter size-full wp-image-161064\" /></p>\n<p class=\"calibre2\">Note we’re talking about <em>visual</em> width here, not acceptable number of characters. The email address field may have a visual width as shown, but should still accept up to 256 characters.</p>\n<h3 class=\"calibre7\" id=\"empty-text-boxes\">Empty Text Boxes</h3>\n<p class=\"calibre2\">Another important aspect of text box spacing is the space they have <em>inside</em>. This empty space is how users know they need to type something in there.</p>\n<p class=\"calibre2\">Way too many forms have text boxes that <em>aren’t</em> empty. The two main culprits are:</p>\n<ol>\n<li class=\"calibre3\">background color</li>\n<li class=\"calibre3\">placeholder text.</li>\n</ol>\n<h4 class=\"calibre8\" id=\"no-background-color\">No Background Color</h4>\n<p class=\"calibre2\"><strong class=\"calibre4\">Do not give your fields a background color</strong>. Background color in fields makes them look like buttons (just as buttons without background color look like fields):</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508853382BackgroundFields1.png\" alt=\"On this form, background color makes fields look like buttons, and vice versa\" width=\"180\" height=\"274\" class=\"aligncenter size-full wp-image-161065\" /></p>\n<p class=\"figcaption\">On this form, background color makes fields look like buttons, and vice versa.</p>\n<p class=\"calibre2\">A simple border on four sides is enough to show users where to type:</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508853413BackgroundFields2.png\" alt=\"You don’t need much to show users where their answers go\" width=\"265\" height=\"291\" class=\"aligncenter size-full wp-image-161066\" /></p>\n<p class=\"figcaption\">You don’t need much to show users where their answers go.</p>\n<p class=\"calibre2\">Just make sure your border can be seen:</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508854149BackgroundFields3.png\" alt=\"The field borders on this form are so light they’re nearly impossible to see\" width=\"325\" height=\"355\" class=\"aligncenter size-full wp-image-161067\" /></p>\n<p class=\"figcaption\">The field borders on this form are so light they’re nearly impossible to see.</p>\n","protected":false},"author":71764,"featured_media":161149,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[8572,6131,8597,8599,8005,8603,412],"tags":[8948,16,1097],"_links":{"self":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/posts/161052"}],"collection":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/posts"}],"about":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/types/post"}],"author":[{"embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/users/71764"}],"replies":[{"embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/comments?post=161052"}],"version-history":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/posts/161052/revisions"}],"wp_featuredmedia":[{"embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/media/161149"}],"wp_attachment":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/media?parent=161052"}],"wp_term":[{"taxonomy":"category","embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/categories?post=161052"},{"taxonomy":"post_tag","embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/tags?post=161052"}],"curies":[{"name":"wp","href":"https://api.w.org/{rel}","templated":true}]}}
{"index":{"_index":"blogs","_id":160934,"_type":"default"}}
{"id":160934,"date":"2017-10-30T09:00:43","date_gmt":"2017-10-30T16:00:43","guid":{"rendered":"https://www.sitepoint.com/?p=160934"},"modified":"2017-10-26T20:42:08","modified_gmt":"2017-10-27T03:42:08","slug":"designing-form-layout-alignment","status":"publish","type":"post","link":"https://www.sitepoint.com/designing-form-layout-alignment/","title":{"rendered":"Designing Form Layout: Alignment"},"content":{"rendered":"<p><em>The following is a short extract from our book, <a href=\"https://www.sitepoint.com/premium/books/designing-ux-forms\">Designing UX: Forms</a>, written by Jessica Enders. It’s the ultimate guide to form design, a key part of effective UX design. SitePoint Premium members get access with their membership, or you can buy a copy in stores worldwide.</em></p>\n<p class=\"calibre2\">You and a friend are each driving to a restaurant for dinner. Both of your routes go down a highway with two lanes. The highways are the same length. On your route, all the slow cars are doing the right thing and sticking to one lane, so you can whizz past in the other. On your friend’s route, the slow cars are scattered across both lanes of the highway, so she has to weave in and out. Which one of you will get to the restaurant first?</p>\n<h3 class=\"calibre7\" id=\"vertical-path-to-completion\">Vertical Path to Completion</h3>\n<p class=\"calibre2\">A straight, unobstructed route is fastest for driving, and also for form filling. So your next step is to vertically line up all your form fields, as well as the main button on the page (called the <strong class=\"calibre4\">primary action button</strong>):</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508509841BankExample6.png\" alt=\"/>Answer fields and the primary action button are vertically aligned” width=”998″ height=”1000″ class=”aligncenter size-full wp-image-160935″ /></p>\n<p class=\"calibre2\">Now you’ve created a straight, unobstructed, vertical path to completion. Not only have you made it faster for your form to be filled out, it looks neater and simpler too. (We’ll talk about the distance between some fields and their labels shortly.)</p>\n<h4 class=\"calibre8\" id=\"don-t-put-questions-beside-each-other\">Don’t Put Questions Beside Each Other</h4>\n<p class=\"calibre2\">Because a vertical path to completion makes a form longer, you may be tempted to squeeze some questions next to each other:</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508509900QuestionsBeside.png\" alt=\"In this form, the Security Code and Postal Code questions have been put beside other questions\" width=\"500\" height=\"441\" class=\"aligncenter size-full wp-image-160936\" /></p>\n<p class=\"figcaption\">In this form, the Security Code and Postal Code questions have been put beside other questions</p>\n<p class=\"calibre2\">This is a bad idea, for the following reasons:</p>\n<ul class=\"credits\">\n<li class=\"calibre3\">It interrupts the smooth flow through the form (like a broken down car in your fast lane).</li>\n<li class=\"calibre3\">Users will often not see the question on the right-hand side, because it’s outside the focus of their vision (this is only about nine characters wide).</li>\n<li class=\"calibre3\">It prevents the form from working seamlessly on both large and small screens. (More on this shortly.)</li>\n</ul>\n<p class=\"calibre2\">Also, as you may recall from Chapter 3, for users it’s the <em>perceived</em> length of the form, not the actual length, that matters. The vertical path to completion makes form filling not only objectively faster, but it makes it <em>feel</em> fast.</p>\n<h3 class=\"calibre7\" id=\"aligning-answer-fields\">Aligning Answer Fields</h3>\n<p class=\"calibre2\">One way you can sometimes save space, however, is with answer fields. Look at the answer fields for the marketing consent question:</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508509960MarketingConsent1.png\" alt=\"Marketing consent question, with vertical answer fields\" width=\"737\" height=\"68\" class=\"aligncenter size-full wp-image-160937\" /></p>\n<p class=\"calibre2\">Whenever the answer fields are small, we can put them horizontally. (For this purpose we define “small” as three or fewer options, all with short labels.) The form will still work for touch, and on small screens. Marketing consent is just such a question:</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508509995MarketingConsent2.png\" alt=\"Marketing consent question, with horizontal answer fields\" width=\"802\" height=\"56\" class=\"aligncenter size-full wp-image-160938\" /></p>\n<p class=\"calibre2\">In fact, date of birth is also a question with small answer fields. You may not have realized we’ve already put them on one line:</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508510031DateOfBirth.png\" alt=\"The date of birth question has three small answer fields\" width=\"273\" height=\"27\" class=\"aligncenter size-full wp-image-160939\" /></p>\n<p class=\"calibre17\">But remember: you can only put answer fields beside each other if they’re small. Otherwise, the design won’t work in some cases. Social networking, for instance, has quite a large number of answer options. If we try to put them horizontally, they’ll go off the edge—especially on mobile—and invoke the dreaded horizontal scrollbar:</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508510070SocialNetworking.png\" alt=\"If we position a long set of answer fields horizontally, we’re likely to conjure the horizontal scrollbar, even on larger screens\" width=\"998\" height=\"750\" class=\"aligncenter size-full wp-image-160940\" /></p>\n<p class=\"figcaption\">If we position a long set of answer fields horizontally, we’re likely to conjure the horizontal scrollbar, even on larger screens</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508510108SocialNetworkingMobile.png\" alt=\"If our answer fields aren’t small, it’s even more likely we’ll cause the horizontal scrollbar to appear on mobile\" width=\"197\" height=\"400\" class=\"aligncenter size-full wp-image-160941\" /></p>\n<p class=\"figcaption\">If our answer fields aren’t small, it’s even more likely we’ll cause the horizontal scrollbar to appear on mobile.</p>\n<p class=\"calibre17\">Assuming we can’t build a custom widget, it’s better to leave these as a single vertical list:</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508510145BankExample7.png\" alt=\"Larger sets of radio buttons or checkboxes should be vertically aligned\" width=\"998\" height=\"976\" class=\"aligncenter size-full wp-image-160942\" /></p>\n<p class=\"figcaption\">Larger sets of radio buttons or checkboxes should be vertically aligned.</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508510181BankExample7Mobile1.png\" alt=\"Vertical alignment of sets of radio buttons or checkboxes works on mobile too\" width=\"197\" height=\"400\" class=\"aligncenter size-full wp-image-160943\" /></p>\n<p class=\"figcaption\">Vertical alignment of sets of radio buttons or checkboxes works on mobile too.</p>\n<h3 class=\"calibre7\" id=\"label-placement\">Label Placement</h3>\n<p class=\"calibre17\">There’s a problem with the mobile view of our form, which you may have noticed from some of the illustrations above. On a small screen, when the focus is in a text box, the corresponding label isn’t visible, just like this example:</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508510222NoLabel.png\" alt=\"Labels on the left are seen initially but disappear when the user starts to fill in the form\" width=\"550\" height=\"409\" class=\"aligncenter size-full wp-image-160944\" /></p>\n<p class=\"figcaption\">Labels on the left are seen initially but disappear when the user starts to fill in the form.</p>\n<p class=\"calibre2\">We could avoid this problem by always putting the labels above the fields. But this creates a new problem: the form becomes a lot longer visually.</p>\n<p class=\"calibre17\">Here’s how it would look on a large screen:</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508510253BankExample8.png\" alt=\"Forms are longer when labels are positioned above fields\" width=\"998\" height=\"1314\" class=\"aligncenter size-full wp-image-160945\" /></p>\n<p class=\"figcaption\">Forms are longer when labels are positioned above fields.</p>\n<p class=\"calibre2\">What you need to do is code the form to be <em>responsive</em>. <strong class=\"calibre4\">When the screen is larger, labels should go to the left of fields; when the screen is smaller, labels should go above fields.</strong> That way, we make use of the space we have on larger screens, while ensuring the form can also be filled out on smaller screens.</p>\n<p class=\"calibre2\">If we code our example form to be responsive, this is how it would look on a mobile:</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508510285BankExample7Mobile2.png\" alt=\"On mobile, labels are positioned above the fields so they’re visible when you need them\" width=\"197\" height=\"400\" class=\"aligncenter size-full wp-image-160946\" /></p>\n<p class=\"figcaption\">On mobile, labels are positioned above the fields so they’re visible when you need them.</p>\n<p class=\"calibre17\">This is how it would look on a larger screen:</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508510316BankExample7.png\" alt=\"On larger screens, labels are positioned to the left of fields so the form doesn’t look unnecessarily long.\" width=\"998\" height=\"976\" class=\"aligncenter size-full wp-image-160947\" /></p>\n<p class=\"calibre17\">Here’s a real-world example of responsive form labels—first the larger screen version of the form, then the smaller screen:</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508510360ResponsiveLabels1.png\" alt=\"On larger screens, labels are to the left of fields, so the form appears nice and short\" width=\"350\" height=\"401\" class=\"aligncenter size-full wp-image-160948\" /></p>\n<p class=\"figcaption\">On larger screens, labels are to the left of fields, so the form appears nice and short.</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508510386ResponsiveLabels2.png\" alt=\"On smaller screens, labels are above fields, so they’re always in view<\" width=\"300\" height=\"534\" class=\"aligncenter size-full wp-image-160949\" /></p>\n<p class=\"figcaption\">On smaller screens, labels are above fields, so they’re always in view.</p>\n<h4 class=\"calibre8\" id=\"what-about-that-study-\">What about <em>That</em> Study?</h4>\n<p class=\"calibre2\">One of the most popular articles on the UXMatters website, and quoted in Luke Wroblewski’s book and articles, is <a href=\"http://www.uxmatters.com/mt/archives/2006/07/label-placement-in-forms.php\">an eyetracking study by Matteo Penzo</a>. This study is frequently used as evidence that labels should <em>never</em> go to the left of fields, but always above.</p>\n<p class=\"calibre2\">The problem is, you should never base design decisions on a single study, especially one with an unknown methodology, and very minor differences in results! Instead, you need to weigh up all the different pros and cons, based on theory and observations from user research. When you do this, it’s clear that—on a large screen—the benefits of having labels to the left of the fields outweigh the costs. It’s worth a very minor increase in eye movement to have a form that’s half as long.</p>\n<h4 class=\"calibre8\" id=\"avoiding-the-gutter\">Avoiding the Gutter</h4>\n<p class=\"calibre2\">In addition to what’s been said already, there are two ways you can increase the usability of your form when you have labels to the left of your fields. These techniques are important to prevent a big “gutter” appearing between the labels and their answer fields:</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508517261BigGap.png\" alt=\"For many questions on our example form, the label is far away from the corresponding answer fields\" width=\"998\" height=\"976\" class=\"aligncenter size-full wp-image-160951\" /></p>\n<p class=\"figcaption\">For many questions on our example form, the label is far away from the corresponding answer fields.</p>\n<p class=\"calibre2\">These gaps can make it hard for the user to associate labels with their answer fields.</p>\n<p class=\"calibre17\">If the labels are mostly short, you can set them flush right, so they’re next to the fields:</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508517305BankExample9.png\" alt=\"Labels set flush right\" width=\"998\" height=\"982\" class=\"aligncenter size-full wp-image-160952\" /></p>\n<p class=\"figcaption\">Labels set flush right.</p>\n<p class=\"calibre17\">If the labels are mostly longer, they’ll get hard to read if they’re flush right. In this case, set them flush left (like normal text) but add zebra striping to your form:</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508517339BankExample10.png\" alt=\"Zebra striping behind labels set flush left\" width=\"998\" height=\"976\" class=\"aligncenter size-full wp-image-160953\" /></p>\n<p class=\"figcaption\">Zebra striping behind labels set flush left.</p>\n<p class=\"calibre2\"><strong class=\"calibre4\">Zebra striping</strong> is the faint shading you see behind every second question. It helps the eye connect the label to the field (as demonstrated by <a href=\"http://alistapart.com/article/zebrastripingdoesithelp\">a study I conducted a while back</a>, and <a href=\"http://alistapart.com/article/zebrastripingmoredataforthecase\">its follow up</a>).</p>\n<p class=\"calibre2\">(If you want to read more about label placement, I wrote <a href=\"https://www.sitepoint.com/definitive-guide-form-label-positioning/\">a detailed article on the SitePoint website</a>, and <a href=\"http://www.formulate.com.au/blog/eyetracking-research-and-form-design\">provided some commentary on my own website</a> too.)</p>\n<h3 class=\"calibre7\" id=\"button-alignment\">Button Alignment</h3>\n<h4 class=\"calibre8\" id=\"single-step-forms\">Single-step Forms</h4>\n<p class=\"calibre2\">If you have just one primary action, line it up with your fields for fast completion. This is what we’ve done with our example form:</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508517385ButtonAlignment.png\" alt=\"Left edge of the primary action button lines up with the left edge of the fields\" width=\"998\" height=\"1018\" class=\"aligncenter size-full wp-image-160954\" /></p>\n<p class=\"figcaption\">Left edge of the primary action button lines up with the left edge of the fields.</p>\n<h4 class=\"calibre8\" id=\"multi-step-forms\">Multistep Forms</h4>\n<p class=\"calibre2\">If your form goes over multiple steps, you’ll need to provide buttons for the user to move between steps. One option is to put the next button in line with the fields, consistent with our single-step forms:</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508517416MultiStep1.png\" alt=\"Next is our primary action, so it’s vertically aligned with the fields\" width=\"818\" height=\"311\" class=\"aligncenter size-full wp-image-160955\" /></p>\n<p class=\"figcaption\">Next is our primary action, so it’s vertically aligned with the fields.</p>\n<p class=\"calibre2\">Another option is to put the next button to the right and the previous button to the left (for an English-speaking audience):</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508517444MultiStep2.png\" alt=\"English speakers typically think of right as forward and left as backward, so we can align our buttons this way\" width=\"600\" height=\"62\" class=\"aligncenter size-full wp-image-160956\" /></p>\n<p class=\"figcaption\">English speakers typically think of right as forward and left as backward, so we can align our buttons this way.</p>\n<p class=\"calibre2\">Both approaches have been shown to work well, but it can depend on the context. If you’re not sure which is right for your form, run some usability tests with your target audience.</p>\n<p class=\"calibre2\">(You can also put multistep forms into an accordion, but accordions have a number of usability issues so are best avoided.)</p>\n<h4 class=\"calibre8\" id=\"buttons-on-mobile\">Buttons on Mobile</h4>\n<p class=\"calibre2\">On small screens, you may want to design your buttons to be responsive, so that they:</p>\n<ul class=\"credits\">\n<li class=\"calibre3\">are stacked, with the primary action on top</li>\n<li class=\"calibre3\">take up the full width of the screen, except for a little bit of whitespace on either side (so that they’re still clearly buttons).</li>\n</ul>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508517498BankExample10Mobile.png\" alt=\"Coding our form to be responsive to screen size, we can make sure buttons still work well on mobile\" width=\"197\" height=\"400\" class=\"aligncenter size-full wp-image-160957\" /></p>\n<p class=\"figcaption\">Coding our form to be responsive to screen size, we can make sure buttons still work well on mobile.</p>\n<p class=\"calibre2\">By now our form is looking really good, and is highly usable to boot. But there are further improvements we can make, which we’ll explaore next</p>\n","protected":false},"excerpt":{"rendered":"<p><em>The following is a short extract from our book, <a href=\"https://www.sitepoint.com/premium/books/designing-ux-forms\">Designing UX: Forms</a>, written by Jessica Enders. It’s the ultimate guide to form design, a key part of effective UX design. SitePoint Premium members get access with their membership, or you can buy a copy in stores worldwide.</em></p>\n<p class=\"calibre2\">You and a friend are each driving to a restaurant for dinner. Both of your routes go down a highway with two lanes. The highways are the same length. On your route, all the slow cars are doing the right thing and sticking to one lane, so you can whizz past in the other. On your friend’s route, the slow cars are scattered across both lanes of the highway, so she has to weave in and out. Which one of you will get to the restaurant first?</p>\n<h3 class=\"calibre7\" id=\"vertical-path-to-completion\">Vertical Path to Completion</h3>\n<p class=\"calibre2\">A straight, unobstructed route is fastest for driving, and also for form filling. So your next step is to vertically line up all your form fields, as well as the main button on the page (called the <strong class=\"calibre4\">primary action button</strong>):</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508509841BankExample6.png\" alt=\"/>Answer fields and the primary action button are vertically aligned” width=”998″ height=”1000″ class=”aligncenter size-full wp-image-160935″ /></p>\n<p class=\"calibre2\">Now you’ve created a straight, unobstructed, vertical path to completion. Not only have you made it faster for your form to be filled out, it looks neater and simpler too. (We’ll talk about the distance between some fields and their labels shortly.)</p>\n<h4 class=\"calibre8\" id=\"don-t-put-questions-beside-each-other\">Don’t Put Questions Beside Each Other</h4>\n<p class=\"calibre2\">Because a vertical path to completion makes a form longer, you may be tempted to squeeze some questions next to each other:</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508509900QuestionsBeside.png\" alt=\"In this form, the Security Code and Postal Code questions have been put beside other questions\" width=\"500\" height=\"441\" class=\"aligncenter size-full wp-image-160936\" /></p>\n<p class=\"figcaption\">In this form, the Security Code and Postal Code questions have been put beside other questions</p>\n<p class=\"calibre2\">This is a bad idea, for the following reasons:</p>\n<ul class=\"credits\">\n<li class=\"calibre3\">It interrupts the smooth flow through the form (like a broken down car in your fast lane).</li>\n<li class=\"calibre3\">Users will often not see the question on the right-hand side, because it’s outside the focus of their vision (this is only about nine characters wide).</li>\n<li class=\"calibre3\">It prevents the form from working seamlessly on both large and small screens. (More on this shortly.)</li>\n</ul>\n<p class=\"calibre2\">Also, as you may recall from Chapter 3, for users it’s the <em>perceived</em> length of the form, not the actual length, that matters. The vertical path to completion makes form filling not only objectively faster, but it makes it <em>feel</em> fast.</p>\n<h3 class=\"calibre7\" id=\"aligning-answer-fields\">Aligning Answer Fields</h3>\n<p class=\"calibre2\">One way you can sometimes save space, however, is with answer fields. Look at the answer fields for the marketing consent question:</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508509960MarketingConsent1.png\" alt=\"Marketing consent question, with vertical answer fields\" width=\"737\" height=\"68\" class=\"aligncenter size-full wp-image-160937\" /></p>\n<p class=\"calibre2\">Whenever the answer fields are small, we can put them horizontally. (For this purpose we define “small” as three or fewer options, all with short labels.) The form will still work for touch, and on small screens. Marketing consent is just such a question:</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508509995MarketingConsent2.png\" alt=\"Marketing consent question, with horizontal answer fields\" width=\"802\" height=\"56\" class=\"aligncenter size-full wp-image-160938\" /></p>\n<p class=\"calibre2\">In fact, date of birth is also a question with small answer fields. You may not have realized we’ve already put them on one line:</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508510031DateOfBirth.png\" alt=\"The date of birth question has three small answer fields\" width=\"273\" height=\"27\" class=\"aligncenter size-full wp-image-160939\" /></p>\n<p class=\"calibre17\">But remember: you can only put answer fields beside each other if they’re small. Otherwise, the design won’t work in some cases. Social networking, for instance, has quite a large number of answer options. If we try to put them horizontally, they’ll go off the edge—especially on mobile—and invoke the dreaded horizontal scrollbar:</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508510070SocialNetworking.png\" alt=\"If we position a long set of answer fields horizontally, we’re likely to conjure the horizontal scrollbar, even on larger screens\" width=\"998\" height=\"750\" class=\"aligncenter size-full wp-image-160940\" /></p>\n<p class=\"figcaption\">If we position a long set of answer fields horizontally, we’re likely to conjure the horizontal scrollbar, even on larger screens</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508510108SocialNetworkingMobile.png\" alt=\"If our answer fields aren’t small, it’s even more likely we’ll cause the horizontal scrollbar to appear on mobile\" width=\"197\" height=\"400\" class=\"aligncenter size-full wp-image-160941\" /></p>\n<p class=\"figcaption\">If our answer fields aren’t small, it’s even more likely we’ll cause the horizontal scrollbar to appear on mobile.</p>\n<p class=\"calibre17\">Assuming we can’t build a custom widget, it’s better to leave these as a single vertical list:</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508510145BankExample7.png\" alt=\"Larger sets of radio buttons or checkboxes should be vertically aligned\" width=\"998\" height=\"976\" class=\"aligncenter size-full wp-image-160942\" /></p>\n<p class=\"figcaption\">Larger sets of radio buttons or checkboxes should be vertically aligned.</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508510181BankExample7Mobile1.png\" alt=\"Vertical alignment of sets of radio buttons or checkboxes works on mobile too\" width=\"197\" height=\"400\" class=\"aligncenter size-full wp-image-160943\" /></p>\n<p class=\"figcaption\">Vertical alignment of sets of radio buttons or checkboxes works on mobile too.</p>\n<h3 class=\"calibre7\" id=\"label-placement\">Label Placement</h3>\n<p class=\"calibre17\">There’s a problem with the mobile view of our form, which you may have noticed from some of the illustrations above. On a small screen, when the focus is in a text box, the corresponding label isn’t visible, just like this example:</p>\n","protected":false},"author":71764,"featured_media":161146,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[6131,8597,8599,2914,8005,8603,412,8601],"tags":[16,3119,1097],"_links":{"self":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/posts/160934"}],"collection":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/posts"}],"about":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/types/post"}],"author":[{"embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/users/71764"}],"replies":[{"embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/comments?post=160934"}],"version-history":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/posts/160934/revisions"}],"wp_featuredmedia":[{"embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/media/161146"}],"wp_attachment":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/media?parent=160934"}],"wp_term":[{"taxonomy":"category","embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/categories?post=160934"},{"taxonomy":"post_tag","embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/tags?post=160934"}],"curies":[{"name":"wp","href":"https://api.w.org/{rel}","templated":true}]}}
{"index":{"_index":"blogs","_id":161170,"_type":"default"}}
{"id":161170,"date":"2017-10-30T09:00:18","date_gmt":"2017-10-30T16:00:18","guid":{"rendered":"https://www.sitepoint.com/?p=161170"},"modified":"2017-10-29T15:27:15","modified_gmt":"2017-10-29T22:27:15","slug":"optimize-mysql-indexes-slow-queries-configuration","status":"publish","type":"post","link":"https://www.sitepoint.com/optimize-mysql-indexes-slow-queries-configuration/","title":{"rendered":"How to Optimize MySQL: Indexes, Slow Queries, Configuration"},"content":{"rendered":"<p>MySQL is still the world’s most popular relational database, and yet, it’s still the most unoptimized – many people leave it at default values, not bothering to investigate further. In this article, we’ll look at some MySQL optimization tips we’ve covered previously, and combine them with novelties that came out since.</p>\n\n<h2 id=\"configurationoptimization\">Configuration Optimization</h2>\n<p>The first – and most skipped! – performance upgrade every user of MySQL should do is tweak the configuration. 5.7 (the current version) has much better defaults than its predecessors, but it’s still easy to make improvements on top of those. </p>\n<p>We’ll assume you’re using a Linux-based host or a good <a href=\"http://www.sitepoint.com/re-introducing-vagrant-right-way-start-php/\">Vagrant</a> box like our <a href=\"http://www.sitepoint.com/quick-tip-get-homestead-vagrant-vm-running/\">Homestead Improved</a> so your configuration file will be in <code>/etc/mysql/my.cnf</code>. It’s possible that your installation will actually load a secondary configuration file into that configuration file, so look into that – if the <code>my.cnf</code> file doesn’t have much content, the file <code>/etc/mysql/mysql.conf.d/mysqld.cnf</code> might.</p>\n<h3 id=\"editingconfiguration\">Editing Configuration</h3>\n<p>You’ll need to be comfortable with using the command line. Even if you haven’t been exposed to it yet, now is as good a time as any.</p>\n<p>If you’re editing locally on a Vagrant box, you can copy the file out into the main filesystem by copying it into the shared folder with <code>cp /etc/mysql/my.cnf /home/vagrant/Code</code> and editing it with a regular text editor, then copying it back into place when done. Otherwise, use a simple text editor like vim by executing <code>sudo vim /etc/mysql/my.cnf</code>.</p>\n<p><em>Note: modify the above path to match the config file’s real location – it’s possible that it’s actually in <code>/etc/mysql/mysql.conf.d/mysqld.cnf</code></em></p>\n<h3 id=\"manualtweaks\">Manual Tweaks</h3>\n<p>The following manual tweaks should be made out of the box. As per <a href=\"https://www.percona.com/blog/2016/10/12/mysql-5-7-performance-tuning-immediately-after-installation/\">these tips</a>, add this to the config file under the <code>[mysqld]</code> section:</p>\n<pre><code class=\"cnf language-cnf\">innodb_buffer_pool_size = 1G # (adjust value here, 50%-70% of total RAM)\r\ninnodb_log_file_size = 256M\r\ninnodb_flush_log_at_trx_commit = 1 # may change to 2 or 0\r\ninnodb_flush_method = O_DIRECT\r\n</code></pre>\n<ul>\n<li><code>innodb_buffer_pool_size</code> – the buffer pool is a storage area for caching data and indexes in memory. It’s used to keep frequently accessed data in memory, and when you’re running a dedicated or virtual server where the DB will often be the bottleneck, it makes sense to give this part of your app(s) the most RAM. Hence, we give it 50-70% of all RAM. There’s a buffer pool sizing guide available in the <a href=\"https://dev.mysql.com/doc/refman/5.7/en/innodb-buffer-pool-resize.html\">MySQL docs</a>.</li>\n<li>the log file size is well explained <a href=\"https://www.percona.com/blog/2016/05/31/what-is-a-big-innodb_log_file_size/\">here</a> but in a nutshell it’s how much data to store in a log before wiping it. Note that a log in this case is not an error log or something you might be used to, but instead it indicates checkpoint time because with MySQL, writes happen in the background but still affect foreground performance. Big log files mean better performance because of fewer new and smaller checkpoints being created, but longer recovery time in case of a crash (more stuff needs to be re-written to the DB).</li>\n<li><code>innodb_flush_log_at_trx_commit</code> is explained <a href=\"https://dev.mysql.com/doc/refman/5.7/en/innodb-parameters.html#sysvar_innodb_flush_log_at_trx_commit\">here</a> and indicates what happens with the log file. With 1 we have the safest setting, because the log is flushed to disk after every transaction. With 0 or 2 it’s less ACID, but more performant. The difference in this case isn’t big enough to outweigh the stability benefits of the setting of 1.</li>\n<li><code>innodb_flush_method</code> – to top things off in regards to flushing, this gets set to <code>O_DIRECT</code> to avoid double-buffering. This should always be done, unless the I/O system is very low performance. On most hosted servers like DigitalOcean droplets you’ll have SSDs, so the I/O system will be high performance.</li>\n</ul>\n<p>There’s another tool from Percona which can help us find the remaining problems automatically. Note that if we had run it without the above manual tweaks, only 1 out of 4 fixes would have been manually identified because the other 3 depend on user preference and the app’s environment.</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1509294383superhero-534120_1280.jpg\" alt=\"Superhero speeding\" /></p>\n<h3 id=\"variableinspector\">Variable Inspector</h3>\n<p>To install the variable inspector on Ubuntu:</p>\n<pre><code class=\"bash language-bash\">wget https://repo.percona.com/apt/percona-release_0.1-4.$(lsb_release -sc)_all.deb\r\nsudo dpkg -i percona-release_0.1-4.$(lsb_release -sc)_all.deb\r\nsudo apt-get update\r\nsudo apt-get install percona-toolkit\r\n</code></pre>\n<p>For other systems, follow <a href=\"https://www.percona.com/downloads/percona-toolkit/LATEST/\">instructions</a>.</p>\n<p>Then, run the toolkit with:</p>\n<pre><code class=\"bash language-bash\">pt-variable-advisor h=localhost,u=homestead,p=secret\r\n</code></pre>\n<p>You should see output not unlike this one:</p>\n<pre><code class=\"bash language-bash\"># WARN delay_key_write: MyISAM index blocks are never flushed until necessary.\r\n\r\n# NOTE max_binlog_size: The max_binlog_size is smaller than the default of 1GB.\r\n\r\n# NOTE sort_buffer_size-1: The sort_buffer_size variable should generally be left at its default unless an expert determines it is necessary to change it.\r\n\r\n# NOTE innodb_data_file_path: Auto-extending InnoDB files can consume a lot of disk space that is very difficult to reclaim later.\r\n\r\n# WARN log_bin: Binary logging is disabled, so point-in-time recovery and replication are not possible.\r\n</code></pre>\n<p>None of these are critical, they don’t need to be fixed. The only one we could add would be binary logging for replication and snapshot purposes.</p>\n<p><em>Note: the binlog size will default to 1G in newer versions and won’t be noted by PT.</em></p>\n<pre><code class=\"cnf language-cnf\">max_binlog_size = 1G\r\nlog_bin = /var/log/mysql/mysql-bin.log\r\nserver-id=master-01\r\nbinlog-format = 'ROW'\r\n</code></pre>\n<ul>\n<li>the <code>max_binlog_size</code> setting determined how large binary logs will be. These are logs that log your transactions and queries and make checkpoints. If a transaction is bigger than max, then a log might be bigger than max when saved to disk – otherwise, MySQL will keep them at that limit.</li>\n<li>the <code>log_bin</code> option enables binary logging altogether. Without it, there’s no snapshotting or replication. Note that this can be very strenuous on the disk space. Server ID is a necessary option when activating binary logging, so the logs know which server they came from (for replication) and the format is just the way in which the logs are written.</li>\n</ul>\n<p>As you can see, the new MySQL has sane defaults that make things nearly production ready. Of course, every app is different and has additional custom tweaks applicable.</p>\n<h3 id=\"mysqltuner\">MySQL Tuner</h3>\n<p>The <a href=\"https://raw.githubusercontent.com/major/MySQLTuner-perl/master/mysqltuner.pl\">Tuner</a> will monitor a database in longer intervals (run it once per week or so on a live app) and suggest changes based on what it’s seen in the logs.</p>\n<p>Install it by simply downloading it:</p>\n<pre><code class=\"bash language-bash\">wget https://raw.githubusercontent.com/major/MySQLTuner-perl/master/mysqltuner.pl\r\nchmod +x mysqltuner.pl\r\n</code></pre>\n<p>Running it with <code>./mysqltuner.pl</code> will ask you for admin username and password for the database, and output information from the quick scan. For example, here’s my InnoDB section:</p>\n<pre><code class=\"bash language-bash\">[--] InnoDB is enabled.\r\n[--] InnoDB Thread Concurrency: 0\r\n[OK] InnoDB File per table is activated\r\n[OK] InnoDB buffer pool / data size: 1.0G/11.2M\r\n[!!] Ratio InnoDB log file size / InnoDB Buffer pool size (50 %): 256.0M * 2/1.0G should be equal 25%\r\n[!!] InnoDB buffer pool <= 1G and Innodb_buffer_pool_instances(!=1).\r\n[--] Number of InnoDB Buffer Pool Chunk : 8 for 8 Buffer Pool Instance(s)\r\n[OK] Innodb_buffer_pool_size aligned with Innodb_buffer_pool_chunk_size & Innodb_buffer_pool_instances\r\n[OK] InnoDB Read buffer efficiency: 96.65% (19146 hits/ 19809 total)\r\n[!!] InnoDB Write Log efficiency: 83.88% (640 hits/ 763 total)\r\n[OK] InnoDB log waits: 0.00% (0 waits / 123 writes)\r\n</code></pre>\n<p>Again, it’s important to note that this tool should be run once per week or so as the server has been running. Once a config value is changed and the server restarted, it should be run a week from that point then. It’s a good idea to set up a cronjob to do this for you and send you the results periodically.</p>\n<hr />\n<p>Make sure you restart the mysql server after every configuration change:</p>\n<pre><code class=\"bash language-bash\">sudo service mysql restart\r\n</code></pre>\n<h2 id=\"indexes\">Indexes</h2>\n<p>Next up, let’s focus on Indexes – the main pain point of many hobbyist DB admins! Especially those who immediately jump into ORMs and are thus never truly exposed to raw SQL.</p>\n<p><em>Note: the terms keys and indexes can be used interchangeably.</em></p>\n<p>You can compare MySQL indexes with the index in a book which lets you easily find the correct page that contains the subject you’re looking for. If there weren’t any indexes, you’d have to go through the whole book searching for pages that contain the subject.</p>\n<p>As you can imagine, it’s way faster to search by an index than having to go through each page. Therefore, adding indexes to your database is in general speeding up your select queries. However, the index also has to be created and stored. So the update and insert queries will be slower and it will cost you a bit more disk space. In general, you won’t notice the difference with updating and inserting if you have indexed your table correctly and therefore it’s advisable to add indexes at the right locations.</p>\n<p>Tables which only contain a few rows don’t really benefit from indexing. You can imagine that searching through 5 pages is not much slower then first going to the index, getting the page number and then opening that particular page.</p>\n<p>So how do we find out which indexes to add, and which types of indexes exist?</p>\n<h3 id=\"uniqueprimaryindexes\">Unique / Primary Indexes</h3>\n<p>Primary indexes are the main indexes of data which are the default way of addressing them. For a user account, that might be a user ID, or a username, even a main email. Primary indexes are unique. Unique indexes are indexes that cannot be repeated in a set of data. </p>\n<p>For example, if a user selected a specific username, no one else should be able to take it. Adding a “unique” index to the <code>username</code> column solves this problem. MySQL will complain if someone else tries to insert a row which has a username that already exists. </p>\n<pre><code class=\"sql language-sql\">...\r\nALTER TABLE `users` \r\nADD UNIQUE INDEX `username` (`username`);\r\n...\r\n</code></pre>\n<p>Primary keys/indexes are usually defined on table creation, and unique indexes are defined after the fact by altering the table.</p>\n<p>Both primary keys and unique keys can be made on a single column or multiple columns at once. For example, if you want to make sure only one username per country can be defined, you make a unique index on both of those columns, like so:</p>\n<pre><code class=\"sql language-sql\">...\r\nALTER TABLE `users`\r\nADD UNIQUE INDEX `usercountry` (`username`, `country`),\r\n...\r\n</code></pre>\n<p>Unique indexes are put onto columns which you’ll address often. So if the user account is frequently requested and you have many user accounts in the database, that’s a good use case.</p>\n<h3 id=\"regularindexes\">Regular Indexes</h3>\n<p>Regular indexes ease lookup. They’re very useful when you need to find data by a specific column or combination of columns fast, but that data doesn’t need to be unique.</p>\n<pre><code class=\"sql language-sql\">...\r\nALTER TABLE `users`\r\nADD INDEX `usercountry` (`username`, `country`),\r\n...\r\n</code></pre>\n<p>The above would make it faster to search for usernames per country.</p>\n<p>Indexes also help with sorting and grouping speed.</p>\n<h3 id=\"fulltextindexes\">Fulltext Indexes</h3>\n<p>FULLTEXT indexes are used for full-text searches. Only the InnoDB and MyISAM storage engines support FULLTEXT indexes and only for CHAR, VARCHAR, and TEXT columns.</p>\n<p>These indexes are very useful for all the text searching you might need to do. Finding words inside of bodies of text is FULLTEXT’s specialty. Use these on posts, comments, descriptions, reviews, etc. if you often allow searching for them in your application.</p>\n<h3 id=\"descendingindexes\">Descending Indexes</h3>\n<p>Not a special type, but an alteration. From version 8+, MySQL supports <a href=\"https://dev.mysql.com/doc/refman/8.0/en/descending-indexes.html\">Descending indexes</a>, which means it can store indexes in descending order. This can come in handy when you have enormous tables that frequently need the last added data first, or prioritize entries that way. Sorting in descending order was always possible, but came at a small performance penalty. This further speeds things up.</p>\n<pre><code class=\"sql language-sql\">CREATE TABLE t (\r\n c1 INT, c2 INT,\r\n INDEX idx1 (c1 ASC, c2 ASC),\r\n INDEX idx2 (c1 ASC, c2 DESC),\r\n INDEX idx3 (c1 DESC, c2 ASC),\r\n INDEX idx4 (c1 DESC, c2 DESC)\r\n);\r\n</code></pre>\n<p>Consider applying DESC to an index when dealing with logs written in the database, posts and comments which are loaded last to first, and similar.</p>\n<h3 id=\"helpertoolsexplain\">Helper Tools: Explain</h3>\n<p>When looking at optimizing queries, the EXPLAIN tool will be priceless. Prefixing a simple query with <code>EXPLAIN</code> will process it in a very in-depth manner, analyze indexes in use, and show you the ratio of hits and misses. You’ll notice how many rows it had to process to get the results you’re looking for.</p>\n<pre><code class=\"sql language-sql\">EXPLAIN SELECT City.Name FROM City\r\nJOIN Country ON (City.CountryCode = Country.Code)\r\nWHERE City.CountryCode = 'IND' AND Country.Continent = 'Asia'\r\n</code></pre>\n<p>You can further extend this with <code>EXTENDED</code>:</p>\n<pre><code class=\"sql language-sql\">EXPLAIN SELECT City.Name FROM City\r\nJOIN Country ON (City.CountryCode = Country.Code)\r\nWHERE City.CountryCode = 'IND' AND Country.Continent = 'Asia'\r\n</code></pre>\n<p>See how to use this and apply the discoveries by reading <a href=\"https://www.sitepoint.com/using-explain-to-write-better-mysql-queries/\">this excellent, detailed post</a>.</p>\n<h3 id=\"helpertoolsperconaforduplicateindexes\">Helper Tools: Percona for Duplicate Indexes</h3>\n<p>The previously installed Percona Toolkit also has a tool for detecting duplicate indexes, which can come in handy when using third party CMSes or just checking if you accidentally added more indexes than needed. For example, the default WordPress installation has duplicate indexes in the <code>wp_posts</code> table:</p>\n<pre><code class=\"bash language-bash\">pt-duplicate-key-checker h=localhost,u=homestead,p=secret\r\n\r\n# ########################################################################\r\n# homestead.wp_posts\r\n# ########################################################################\r\n\r\n# Key type_status_date ends with a prefix of the clustered index\r\n# Key definitions:\r\n# KEY `type_status_date` (`post_type`,`post_status`,`post_date`,`ID`),\r\n# PRIMARY KEY (`ID`),\r\n# Column types:\r\n# `post_type` varchar(20) collate utf8mb4_unicode_520_ci not null default 'post'\r\n# `post_status` varchar(20) collate utf8mb4_unicode_520_ci not null default 'publish'\r\n# `post_date` datetime not null default '0000-00-00 00:00:00'\r\n# `id` bigint(20) unsigned not null auto_increment\r\n# To shorten this duplicate clustered index, execute:\r\nALTER TABLE `homestead`.`wp_posts` DROP INDEX `type_status_date`, ADD INDEX `type_status_date` (`post_type`,`post_status`,`post_date`);\r\n</code></pre>\n<p>As you can see by the last line, it also gives you advice on how to get rid of the duplicate indexes.</p>\n<h3 id=\"helpertoolsperconaforunusedindexes\">Helper Tools: Percona for Unused Indexes</h3>\n<p>Percona can also detect unused indexes. If you’re logging slow queries (see the Bottlenecks section below), you can run the tool and it’ll inspect if these logged queries are using the indexes in the tables involved with the queries.</p>\n<pre><code class=\"bash language-bash\">pt-index-usage /var/log/mysql/mysql-slow.log\r\n</code></pre>\n<p>For detailed usage of this tools, see <a href=\"https://www.percona.com/doc/percona-toolkit/LATEST/pt-index-usage.html\">here</a>.</p>\n<h2 id=\"bottlenecks\">Bottlenecks</h2>\n<p>This section will explain how to detect and monitor for bottlenecks in a database.</p>\n<pre><code class=\"cnf language-cnf\">slow_query_log = /var/log/mysql/mysql-slow.log\r\nlong_query_time = 1\r\nlog-queries-not-using-indexes = 1\r\n</code></pre>\n<p>The above should be added to the configuration. It’ll monitor queries that are longer than 1 second, and those not using indexes.</p>\n<p>Once this log has some data, you can analyze it for index usage with the aforementioned <code>pt-index-usage</code> tool, or the <code>pt-query-digest</code> tool which produces results like these:</p>\n<pre><code class=\"bash language-bash\">pt-query-digest /var/log/mysql/mysql-slow.log\r\n\r\n# 360ms user time, 20ms system time, 24.66M rss, 92.02M vsz\r\n# Current date: Thu Feb 13 22:39:29 2014\r\n# Hostname: *\r\n# Files: mysql-slow.log\r\n# Overall: 8 total, 6 unique, 1.14 QPS, 0.00x concurrency ________________\r\n# Time range: 2014-02-13 22:23:52 to 22:23:59\r\n# Attribute total min max avg 95% stddev median\r\n# ============ ======= ======= ======= ======= ======= ======= =======\r\n# Exec time 3ms 267us 406us 343us 403us 39us 348us\r\n# Lock time 827us 88us 125us 103us 119us 12us 98us\r\n# Rows sent 36 1 15 4.50 14.52 4.18 3.89\r\n# Rows examine 87 4 30 10.88 28.75 7.37 7.70\r\n# Query size 2.15k 153 296 245.11 284.79 48.90 258.32\r\n# ==== ================== ============= ===== ====== ===== ===============\r\n# Profile\r\n# Rank Query ID Response time Calls R/Call V/M Item\r\n# ==== ================== ============= ===== ====== ===== ===============\r\n# 1 0x728E539F7617C14D 0.0011 41.0% 3 0.0004 0.00 SELECT blog_article\r\n# 2 0x1290EEE0B201F3FF 0.0003 12.8% 1 0.0003 0.00 SELECT portfolio_item\r\n# 3 0x31DE4535BDBFA465 0.0003 12.6% 1 0.0003 0.00 SELECT portfolio_item\r\n# 4 0xF14E15D0F47A5742 0.0003 12.1% 1 0.0003 0.00 SELECT portfolio_category\r\n# 5 0x8F848005A09C9588 0.0003 11.8% 1 0.0003 0.00 SELECT blog_category\r\n# 6 0x55F49C753CA2ED64 0.0003 9.7% 1 0.0003 0.00 SELECT blog_article\r\n# ==== ================== ============= ===== ====== ===== ===============\r\n# Query 1: 0 QPS, 0x concurrency, ID 0x728E539F7617C14D at byte 736 ______\r\n# Scores: V/M = 0.00\r\n# Time range: all events occurred at 2014-02-13 22:23:52\r\n# Attribute pct total min max avg 95% stddev median\r\n# ============ === ======= ======= ======= ======= ======= ======= =======\r\n# Count 37 3\r\n# Exec time 40 1ms 352us 406us 375us 403us 22us 366us\r\n# Lock time 42 351us 103us 125us 117us 119us 9us 119us\r\n# Rows sent 25 9 1 4 3 3.89 1.37 3.89\r\n# Rows examine 24 21 5 8 7 7.70 1.29 7.70\r\n# Query size 47 1.02k 261 262 261.25 258.32 0 258.32\r\n# String:\r\n# Hosts localhost\r\n# Users *\r\n# Query_time distribution\r\n# 1us\r\n# 10us\r\n# 100us ################################################################\r\n# 1ms\r\n# 10ms\r\n# 100ms\r\n# 1s\r\n# 10s+\r\n# Tables\r\n# SHOW TABLE STATUS LIKE 'blog_article'\\G\r\n# SHOW CREATE TABLE `blog_article`\\G\r\n# EXPLAIN /*!50100 PARTITIONS*/\r\nSELECT b0_.id AS id0, b0_.slug AS slug1, b0_.title AS title2, b0_.excerpt AS excerpt3, b0_.external_link AS external_link4, b0_.description AS description5, b0_.created AS created6, b0_.updated AS updated7 FROM blog_article b0_ ORDER BY b0_.created DESC LIMIT 10\r\n</code></pre>\n<p>If you’d prefer to analyze these logs by hand, you can do so too – but first you need to export the log into a more “analyzable” format. This can be done with:</p>\n<pre><code class=\"bash language-bash\">mysqldumpslow /var/log/mysql/mysql-slow.log\r\n</code></pre>\n<p>Additional parameters can further filter data and make sure only important things are exported. For example: the top 10 queries sorted by average execution time.</p>\n<pre><code class=\"bash language-bash\">mysqldumpslow -t 10 -s at /var/log/mysql/localhost-slow.log\r\n</code></pre>\n<p>For other parameters, see the <a href=\"https://dev.mysql.com/doc/refman/5.7/en/mysqldumpslow.html\">docs</a>.</p>\n<h2 id=\"conclusion\">Conclusion</h2>\n<p>In this comprehensive MySQL optimization post we looked at various techniques for making MySQL fly. </p>\n<p>We dealt with configuration optimization, we powered through some indexes, and we got rid of some bottlenecks. This was all mostly theoretical, however – for a real world use case of applying these techniques on a real app, stay tuned for our performance month project – coming soon!</p>\n<p>Have we missed any techniques and tips? Let us know!</p>\n","protected":false},"excerpt":{"rendered":"<p>MySQL is still the world’s most popular relational database, and yet, it’s still the most unoptimized – many people leave it at default values, not bothering to investigate further. In this article, we’ll look at some MySQL optimization tips we’ve covered previously, and combine them with novelties that came out since.</p>\n<h2 id=\"configurationoptimization\">Configuration Optimization</h2>\n<p>The first – and most skipped! – performance upgrade every user of MySQL should do is tweak the configuration. 5.7 (the current version) has much better defaults than its predecessors, but it’s still easy to make improvements on top of those. </p>\n<p>We’ll assume you’re using a Linux-based host or a good <a href=\"http://www.sitepoint.com/re-introducing-vagrant-right-way-start-php/\">Vagrant</a> box like our <a href=\"http://www.sitepoint.com/quick-tip-get-homestead-vagrant-vm-running/\">Homestead Improved</a> so your configuration file will be in <code>/etc/mysql/my.cnf</code>. It’s possible that your installation will actually load a secondary configuration file into that configuration file, so look into that – if the <code>my.cnf</code> file doesn’t have much content, the file <code>/etc/mysql/mysql.conf.d/mysqld.cnf</code> might.</p>\n<h3 id=\"editingconfiguration\">Editing Configuration</h3>\n<p>You’ll need to be comfortable with using the command line. Even if you haven’t been exposed to it yet, now is as good a time as any.</p>\n<p>If you’re editing locally on a Vagrant box, you can copy the file out into the main filesystem by copying it into the shared folder with <code>cp /etc/mysql/my.cnf /home/vagrant/Code</code> and editing it with a regular text editor, then copying it back into place when done. Otherwise, use a simple text editor like vim by executing <code>sudo vim /etc/mysql/my.cnf</code>.</p>\n<p><em>Note: modify the above path to match the config file’s real location – it’s possible that it’s actually in <code>/etc/mysql/mysql.conf.d/mysqld.cnf</code></em></p>\n<h3 id=\"manualtweaks\">Manual Tweaks</h3>\n<p>The following manual tweaks should be made out of the box. As per <a href=\"https://www.percona.com/blog/2016/10/12/mysql-5-7-performance-tuning-immediately-after-installation/\">these tips</a>, add this to the config file under the <code>[mysqld]</code> section:</p>\n<pre><code class=\"cnf language-cnf\">innodb_buffer_pool_size = 1G # (adjust value here, 50%-70% of total RAM)\r\ninnodb_log_file_size = 256M\r\ninnodb_flush_log_at_trx_commit = 1 # may change to 2 or 0\r\ninnodb_flush_method = O_DIRECT\r\n</code></pre>\n<ul>\n<li><code>innodb_buffer_pool_size</code> – the buffer pool is a storage area for caching data and indexes in memory. It’s used to keep frequently accessed data in memory, and when you’re running a dedicated or virtual server where the DB will often be the bottleneck, it makes sense to give this part of your app(s) the most RAM. Hence, we give it 50-70% of all RAM. There’s a buffer pool sizing guide available in the <a href=\"https://dev.mysql.com/doc/refman/5.7/en/innodb-buffer-pool-resize.html\">MySQL docs</a>.</li>\n<li>the log file size is well explained <a href=\"https://www.percona.com/blog/2016/05/31/what-is-a-big-innodb_log_file_size/\">here</a> but in a nutshell it’s how much data to store in a log before wiping it. Note that a log in this case is not an error log or something you might be used to, but instead it indicates checkpoint time because with MySQL, writes happen in the background but still affect foreground performance. Big log files mean better performance because of fewer new and smaller checkpoints being created, but longer recovery time in case of a crash (more stuff needs to be re-written to the DB).</li>\n<li><code>innodb_flush_log_at_trx_commit</code> is explained <a href=\"https://dev.mysql.com/doc/refman/5.7/en/innodb-parameters.html#sysvar_innodb_flush_log_at_trx_commit\">here</a> and indicates what happens with the log file. With 1 we have the safest setting, because the log is flushed to disk after every transaction. With 0 or 2 it’s less ACID, but more performant. The difference in this case isn’t big enough to outweigh the stability benefits of the setting of 1.</li>\n<li><code>innodb_flush_method</code> – to top things off in regards to flushing, this gets set to <code>O_DIRECT</code> to avoid double-buffering. This should always be done, unless the I/O system is very low performance. On most hosted servers like DigitalOcean droplets you’ll have SSDs, so the I/O system will be high performance.</li>\n</ul>\n<p>There’s another tool from Percona which can help us find the remaining problems automatically. Note that if we had run it without the above manual tweaks, only 1 out of 4 fixes would have been manually identified because the other 3 depend on user preference and the app’s environment.</p>\n","protected":false},"author":71392,"featured_media":161169,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[186,225,7892,37],"tags":[5946,1060,3759,886,1012,1076,9760,1877],"_links":{"self":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/posts/161170"}],"collection":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/posts"}],"about":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/types/post"}],"author":[{"embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/users/71392"}],"replies":[{"embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/comments?post=161170"}],"version-history":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/posts/161170/revisions"}],"wp_featuredmedia":[{"embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/media/161169"}],"wp_attachment":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/media?parent=161170"}],"wp_term":[{"taxonomy":"category","embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/categories?post=161170"},{"taxonomy":"post_tag","embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/tags?post=161170"}],"curies":[{"name":"wp","href":"https://api.w.org/{rel}","templated":true}]}}
{"index":{"_index":"blogs","_id":160926,"_type":"default"}}
{"id":160926,"date":"2017-10-28T10:00:45","date_gmt":"2017-10-28T17:00:45","guid":{"rendered":"https://www.sitepoint.com/?p=160926"},"modified":"2017-10-26T20:39:58","modified_gmt":"2017-10-27T03:39:58","slug":"undertanding-core-concepts-user-research","status":"publish","type":"post","link":"https://www.sitepoint.com/undertanding-core-concepts-user-research/","title":{"rendered":"Understanding the Core Concepts of User Research"},"content":{"rendered":"<p><em>The following is a short extract from our new book, <a href=\"https://www.sitepoint.com/premium/books/researching-ux-user-research\">Researching UX: User Research</a>, written by James Lang and Emma Howell. It’s the ultimate guide to user research, a key part of effective UX design. SitePoint Premium members get access with their membership, or you can buy a copy in stores worldwide.</em></p>\n<p>This next section is going to get a bit theoretical. Don’t worry: we’ll show you how to apply it later in the chapter. For now, though, you need the basic building blocks of research design.</p>\n<p>In this section, we’re going to run through 10 concepts. Some may already be familiar to you, others less so. They are:</p>\n<ul>\n<li>What is data?</li>\n<li>Qualitative vs. quantitative</li>\n<li>Discovery vs. validation</li>\n<li>Insight vs. evidence vs. ideas</li>\n<li>Validity and representativeness</li>\n<li>Scaling your investment</li>\n<li>Multi-method approaches</li>\n<li>In-the-moment research</li>\n<li>Ethics</li>\n<li>Research as a team sport.</li>\n</ul>\n<h3 id=\"what-is-data-\">What is Data?</h3>\n<p>The research process involves collecting, organising and making sense of data, so it’s a good idea to be clear what we mean by the word ‘data’. Actually, data is just another word for observations, and observations come in many forms, such as:</p>\n<ul>\n<li>Seeing someone behave in a certain way</li>\n<li>Or do something we’re interested in (such as click on a particular button)</li>\n<li>Hearing someone make a particular comment about your product</li>\n<li>Noting that 3,186 people have visited your Contact Us page today</li>\n</ul>\n<p>But how do you know what’s useful data, and what’s just irrelevant detail? That’s what we’ll be covering in the first few chapters, where we’ll talk about how to engage the right people, and how to ask the right questions in the right way. </p>\n<p>And how do you know what to do with data when you’ve got it? We’ll be covering that in the final two chapters about analysis and sharing your findings. In particular, we’ll be showing you how to transform raw data into usable <em>insight</em>, <em>evidence</em> and <em>ideas</em>. </p>\n<h3 id=\"qualitative-vs-quantitative\">Qualitative vs. Quantitative</h3>\n<p>When it comes to data analysis, the approaches we use can be classified as qualitative or quantitative. </p>\n<p>Qualitative questions are concerned with impressions, explanations and feelings, and they tend to begin with why, how or what. Such as:</p>\n<ul>\n<li>“Why don't teenagers use the new skate park?"</li>\n<li>“How do novice cooks bake a cake?”</li>\n<li>“What's the first thing visitors do when they arrive on the homepage?"</li>\n</ul>\n<p>Quantitative questions are concerned with numbers. For example:</p>\n<ul>\n<li>“How many people visited the skate park today?"</li>\n<li>“How long has the cake been in the oven for?</li>\n<li>"How often do you visit the website?"</li>\n</ul>\n<p>Because they answer different questions, and use data in different ways, we also think of research methods as being qualitative or quantitative. Surveys and analytics are in the quantitative camp, while interviews of all sorts are qualitative. In general, you’ll be leaning on qualitative research methods more, so that will be the focus of this book.</p>\n<h3 id=\"discovery-vs-validation\">Discovery vs. Validation</h3>\n<p>The kind of research will depend on where you are in your product or project lifecycle.</p>\n<p>If you’re right at the beginning (in the ‘discovery’ phase), you’ll be needing to answer fundamental questions, such as:</p>\n<ul>\n<li>Who are our potential users?</li>\n<li>Do they have a problem we could be addressing?</li>\n<li>How are they currently solving that problem?</li>\n<li>How can we improve the way they do things?</li>\n</ul>\n<p>If you’re at the validation stage, you have a solution in mind and you need to test it. This might involve:</p>\n<ul>\n<li>Choosing between several competing options</li>\n<li>Checking the implementation of your solution matches the design</li>\n<li>Checking with users that your solution actually solves the problem it’s supposed to.</li>\n</ul>\n<p>What this all means is that your research methods will differ, depending on whether you’re at the discovery stage or the validation stage. If it’s the former, you’ll be wanting to conduct more in-depth, multi-method research with a larger sample, using a mix of both qualitative and quantitative methodologies. If it’s the latter, you’ll be using multiple quick rounds of research with a small sample each time.</p>\n<p>At the risk of confusing matters, it’s worth mentioning that discovery continues to happen during validation – you're always learning about your users and how they solve their problems, so it's important to remain open to this, and adapt earlier learnings to accommodate new knowledge.</p>\n<h3 id=\"insight-evidence-and-ideas\">Insight, Evidence and Ideas</h3>\n<p>Research is pointless unless it’s actually used. In some cases, the purpose of research is purely to provide direction to your team; the output of this kind of project is <em>insight</em>. Perhaps you want to understand users’ needs in the discovery phase of your project. If so, you need insight into their current behaviour and preferences, which you’ll refer to as you design a solution.</p>\n<p>Often, though, you need research to persuade other people, not just enlighten your immediate team. This can be where you need to make a business case, where your approach faces opposition from skeptical stakeholders, or where you need to provide justification for the choices you’ve made. When you need to persuade other people, what you need is <em>evidence</em>. </p>\n<p>And sometimes, your main objective is to generate new <em>ideas</em>. Where that’s the case, rigorous research is still the best foundation, but you’ll want to adjust things slightly to maximise the creativity of your outputs.</p>\n<p>Research is great at producing insight, evidence and ideas. But… methodologies that prioritise one are often weaker on the others, and vice versa. It’s much easier if you plan in advance what you’ll need to collect, and how, rather than leaving it till the end of the project. The takeout: you should think about the balance of insight, evidence and ideas you’ll need from your project, and plan accordingly.</p>\n<p>When it comes to planning your approach, bear in mind your analysis process later on. If you give it thought at this stage, you’ll ensure you’re collecting the right data in the right way. We talk about this more in Chapter 8.</p>\n<h3 id=\"validity\">Validity</h3>\n<p>Validity is another way of saying, “Could I make trustworthy decisions based on these results?” If your research isn’t valid, you might as well not bother. And at the same time, validity is relative. What this means is that every research project is a tradeoff between being as valid as possible, and being realistic about what’s achievable within your timeframe and budget. Designing a research project often comes down to a judgement call between these two considerations.</p>\n<p>Let’s look at an example. You want to understand how Wall Street traders use technology to inform their decision-making. If you were prioritising validity, you might aspire to recruit a sample of several hundred, and use a mix of interviewing and observation to follow their behaviour week by week over several months. That would be extremely valid, but it would also be totally unrealistic:</p>\n<ul>\n<li>Wall Street traders will be rich and busy. They’re unlikely to want to take part in your research.</li>\n<li>A sample of several hundred is huge. You’re unlikely to be able to manage it and process the mountain of data it would generate.</li>\n<li>A duration of several months is ambitious. You would struggle to keep your participants engaged over such a long period.</li>\n<li>Even if the above weren’t issues, the effort and cost involved would be huge.</li>\n</ul>\n<p>Undaunted, you might choose to balance validity and achievability in a different way, by using a smaller number of interviews, over a shorter duration, and appealing to traders’ sense of curiosity rather than offering money as an incentive for taking part. It’s more achievable, but you’ve sacrificed some validity in the process.</p>\n<p>Validity can take several forms. When you design a research project, ask yourself whether your approach is:</p>\n<ul>\n<li><strong>Representative:</strong> Is your sample a cross-section of the group you’re interested in? Watch out for the way you recruit and incentivize participants as a source of bias.</li>\n<li><strong>Realistic:</strong> If you’re asking people to complete a task, is it a fair reflection of what they’d do normally? For example, if you’re getting them to assess a smartphone prototype, don’t ask them to try it on a laptop.</li>\n<li><strong>Knowable:</strong> Sometimes people don’t know why they do things. If that’s the case, it’s not valid to ask them! For example, users may not know why they tend to prefer puzzle games to racing games, but they will probably still take a guess.</li>\n<li><strong>Memorable:</strong> Small details are hard to remember. If you’re asking your participants to recall something, like how many times they’ve looked at their email in the past month, they’ll be unlikely to remember, and therefore your question isn’t valid: you need a different approach, such as one based on analytics. If you were to ask them how many times they’ve been to a funeral in the past month, you can put more trust in their answer.</li>\n<li><strong>In the moment:</strong> If your question isn’t knowable or memorable, it’s still possible to tackle it ‘in the moment’. We’ll say more about this below.</li>\n</ul>\n<p>Takeout: You want your research approach to be as valid as possible (ie, representative and realistic, as well as focused on questions that are knowable and memorable) within the constraints of achievability. Normally, achievability is a matter of time and budget, which leads us to…</p>\n<h3 id=\"scaling-your-investment\">Scaling Your Investment</h3>\n<p>Imagine you were considering changing a paragraph of text on your website. In theory, you could conduct a six-month contextual research project at vast expense, but it probably wouldn’t be worth it. The scale of investment wouldn’t be justified by the value of the change.</p>\n<p>On the other hand, you might have been tasked with launching a game-changing new product on which the future of your organisation depended. You could go and ask two people in the street for their opinion, but that would be a crazy way to inform such a major decision. In this case, the scale of the risk and opportunity justifies a bigger research project.</p>\n<p>So when you look at your research project, ask yourself: what’s the business value of the decisions made with this research? What’s the potential upside? What’s the potential risk? Then scale your research project accordingly. Incidentally, it’s also good practice to refer back to the business impact as a project KPI. You’ll find it much easier to justify the value of your research later on if you can show how it’s made a difference to the business numbers your colleagues care about, such as revenue, conversion rate or Net Promoter Score.</p>\n<h3 id=\"multi-method-approaches\">Multi-Method Approaches</h3>\n<p>You’ll sometimes hear people talking about qualitative and quantitative methods as if they’re in opposition. Not so: they’re friends. And your research projects will always be better if you can combine both, because they counteract each other’s blind spots.</p>\n<p>In fact, all research methods have blind spots. Although you’ve got to make a judgement call about which method to use in any given situation, you should always be aware of its limitations. But the best way to overcome these limitations is to team it up with another approach, so you can have the best of both worlds. Kristy Blazo from U1 Group describes the cycle of qualitative and quantitative stages as a spiral. Each stage builds on the last as you work round it, until you get to the point where the benefits of increased certainty are outweighed by the costs of further research.</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508508385spiral.jpg\" alt=\"The spiral of qualitative and quantitative stages\" width=\"2953\" height=\"1828\" class=\"aligncenter size-full wp-image-160927\" /></p>\n<h3 id=\"in-the-moment-research\">In-The-Moment Research</h3>\n<p>Earlier, we talked about research needing to be knowable and memorable in order to be valid. Actually, that’s not always the case. If you can be present when the event you’re interested in is actually happening, you don’t need to rely on their patchy memory and interpretation to figure out what’s going on.</p>\n<p>Imagine you’re interested in the experience of sports fans at a game. You <em>could</em> interview them afterwards, but it would be more insightful to be there at the event. That way, you could look at the features you’re interested in, and compare your observations to visitors’ own comments. Rather than asking them to recall the state of the toilets and the quality of the catering, you could observe yourself and interview people there and then.</p>\n<p>In-the-moment research, then, gives a more realistic view of events than asking people afterwards. The main methods for in-the-moment research are contextual interviewing and observation, diary studies and analytics, which we’ll talk more about later in this chapter.</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508508425momentresearch.jpg\" alt=\"In-the-moment research\" width=\"1476\" height=\"945\" class=\"aligncenter size-full wp-image-160928\" /></p>\n<p>Takeout: If you’re interested in events and behaviour that people aren’t likely to recall accurately afterwards, you should consider in-the-moment methods, instead of approaches that involve asking them about their experiences weeks or months later, such as depth interviews and surveys.</p>\n<h3 id=\"taking-care\">Taking Care</h3>\n<p>Research has the power to do harm. </p>\n<ul>\n<li>By revealing participants’ identities, you could expose them to consequences in their work or community. Because of this, we hide people’s identities as default.</li>\n<li>Depending on what you’re researching or testing, you risk upsetting people, particularly if they’re young or vulnerable. Because of this, we take care to set up interviews in as unthreatening a way as possible, and ensure participants know they can leave at any point.</li>\n<li>For researchers themselves, there are risks. Visiting participants in their home requires care. Working in a state of deep empathy, sometimes on distressing subjects, can be emotionally hard to deal with, and researchers can and do get burned out as a result. Because of this, we take care with physical safety, and make sure we’re managing the emotional burden together.</li>\n</ul>\n<p>Takeout: When you design your research project, consider the impact it may have on both participants and the project team. If you’re working with adults on an shoe retail website, then this isn’t something you need to worry about too much. But if you’re working with vulnerable teenagers to create an app about domestic violence, then it’s a different story.</p>\n<h3 id=\"research-as-a-team-sport\">Research as a Team Sport</h3>\n<p>Research is most effective when the whole team’s involved. Consider the difference: a project where a researcher takes a brief, goes away for a few weeks, then comes back with a report, versus a project where the whole team decides on the approach together, take turns interviewing and observing all the interviews, and analyse collectively. In the latter, you’re going to have better understanding, greater buy-in, and quicker, more effective results. Research isn’t just about generating insight, evidence or ideas: it’s also about building consensus among a multidisciplinary group who are about to tackle a problem together. The UK’s Government Digital Service calls this ‘research as a team sport’, and that’s the way we think it should be played, too. </p>\n<p>We talk about how to work as a team in Chapter 2, and how to engage and activate the research with your wider group of stakeholders in Chapter 9.</p>\n","protected":false},"excerpt":{"rendered":"<p><em>The following is a short extract from our new book, <a href=\"https://www.sitepoint.com/premium/books/researching-ux-user-research\">Researching UX: User Research</a>, written by James Lang and Emma Howell. It’s the ultimate guide to user research, a key part of effective UX design. SitePoint Premium members get access with their membership, or you can buy a copy in stores worldwide.</em></p>\n<p>This next section is going to get a bit theoretical. Don’t worry: we’ll show you how to apply it later in the chapter. For now, though, you need the basic building blocks of research design.</p>\n<p>In this section, we’re going to run through 10 concepts. Some may already be familiar to you, others less so. They are:</p>\n<ul>\n<li>What is data?</li>\n<li>Qualitative vs. quantitative</li>\n<li>Discovery vs. validation</li>\n<li>Insight vs. evidence vs. ideas</li>\n<li>Validity and representativeness</li>\n<li>Scaling your investment</li>\n<li>Multi-method approaches</li>\n<li>In-the-moment research</li>\n<li>Ethics</li>\n<li>Research as a team sport.</li>\n</ul>\n<h3 id=\"what-is-data-\">What is Data?</h3>\n<p>The research process involves collecting, organising and making sense of data, so it’s a good idea to be clear what we mean by the word ‘data’. Actually, data is just another word for observations, and observations come in many forms, such as:</p>\n<ul>\n<li>Seeing someone behave in a certain way</li>\n<li>Or do something we’re interested in (such as click on a particular button)</li>\n<li>Hearing someone make a particular comment about your product</li>\n<li>Noting that 3,186 people have visited your Contact Us page today</li>\n</ul>\n<p>But how do you know what’s useful data, and what’s just irrelevant detail? That’s what we’ll be covering in the first few chapters, where we’ll talk about how to engage the right people, and how to ask the right questions in the right way. </p>\n<p>And how do you know what to do with data when you’ve got it? We’ll be covering that in the final two chapters about analysis and sharing your findings. In particular, we’ll be showing you how to transform raw data into usable <em>insight</em>, <em>evidence</em> and <em>ideas</em>. </p>\n<h3 id=\"qualitative-vs-quantitative\">Qualitative vs. Quantitative</h3>\n<p>When it comes to data analysis, the approaches we use can be classified as qualitative or quantitative. </p>\n<p>Qualitative questions are concerned with impressions, explanations and feelings, and they tend to begin with why, how or what. Such as:</p>\n<ul>\n<li>“Why don't teenagers use the new skate park?"</li>\n<li>“How do novice cooks bake a cake?”</li>\n<li>“What's the first thing visitors do when they arrive on the homepage?"</li>\n</ul>\n<p>Quantitative questions are concerned with numbers. For example:</p>\n<ul>\n<li>“How many people visited the skate park today?"</li>\n<li>“How long has the cake been in the oven for?</li>\n<li>"How often do you visit the website?"</li>\n</ul>\n<p>Because they answer different questions, and use data in different ways, we also think of research methods as being qualitative or quantitative. Surveys and analytics are in the quantitative camp, while interviews of all sorts are qualitative. In general, you’ll be leaning on qualitative research methods more, so that will be the focus of this book.</p>\n<h3 id=\"discovery-vs-validation\">Discovery vs. Validation</h3>\n<p>The kind of research will depend on where you are in your product or project lifecycle.</p>\n<p>If you’re right at the beginning (in the ‘discovery’ phase), you’ll be needing to answer fundamental questions, such as:</p>\n<ul>\n<li>Who are our potential users?</li>\n<li>Do they have a problem we could be addressing?</li>\n<li>How are they currently solving that problem?</li>\n<li>How can we improve the way they do things?</li>\n</ul>\n<p>If you’re at the validation stage, you have a solution in mind and you need to test it. This might involve:</p>\n<ul>\n<li>Choosing between several competing options</li>\n<li>Checking the implementation of your solution matches the design</li>\n<li>Checking with users that your solution actually solves the problem it’s supposed to.</li>\n</ul>\n<p>What this all means is that your research methods will differ, depending on whether you’re at the discovery stage or the validation stage. If it’s the former, you’ll be wanting to conduct more in-depth, multi-method research with a larger sample, using a mix of both qualitative and quantitative methodologies. If it’s the latter, you’ll be using multiple quick rounds of research with a small sample each time.</p>\n<p>At the risk of confusing matters, it’s worth mentioning that discovery continues to happen during validation – you're always learning about your users and how they solve their problems, so it's important to remain open to this, and adapt earlier learnings to accommodate new knowledge.</p>\n<h3 id=\"insight-evidence-and-ideas\">Insight, Evidence and Ideas</h3>\n<p>Research is pointless unless it’s actually used. In some cases, the purpose of research is purely to provide direction to your team; the output of this kind of project is <em>insight</em>. Perhaps you want to understand users’ needs in the discovery phase of your project. If so, you need insight into their current behaviour and preferences, which you’ll refer to as you design a solution.</p>\n<p>Often, though, you need research to persuade other people, not just enlighten your immediate team. This can be where you need to make a business case, where your approach faces opposition from skeptical stakeholders, or where you need to provide justification for the choices you’ve made. When you need to persuade other people, what you need is <em>evidence</em>. </p>\n<p>And sometimes, your main objective is to generate new <em>ideas</em>. Where that’s the case, rigorous research is still the best foundation, but you’ll want to adjust things slightly to maximise the creativity of your outputs.</p>\n<p>Research is great at producing insight, evidence and ideas. But… methodologies that prioritise one are often weaker on the others, and vice versa. It’s much easier if you plan in advance what you’ll need to collect, and how, rather than leaving it till the end of the project. The takeout: you should think about the balance of insight, evidence and ideas you’ll need from your project, and plan accordingly.</p>\n<p>When it comes to planning your approach, bear in mind your analysis process later on. If you give it thought at this stage, you’ll ensure you’re collecting the right data in the right way. We talk about this more in Chapter 8.</p>\n<h3 id=\"validity\">Validity</h3>\n<p>Validity is another way of saying, “Could I make trustworthy decisions based on these results?” If your research isn’t valid, you might as well not bother. And at the same time, validity is relative. What this means is that every research project is a tradeoff between being as valid as possible, and being realistic about what’s achievable within your timeframe and budget. Designing a research project often comes down to a judgement call between these two considerations.</p>\n<p>Let’s look at an example. You want to understand how Wall Street traders use technology to inform their decision-making. If you were prioritising validity, you might aspire to recruit a sample of several hundred, and use a mix of interviewing and observation to follow their behaviour week by week over several months. That would be extremely valid, but it would also be totally unrealistic:</p>\n<ul>\n<li>Wall Street traders will be rich and busy. They’re unlikely to want to take part in your research.</li>\n<li>A sample of several hundred is huge. You’re unlikely to be able to manage it and process the mountain of data it would generate.</li>\n<li>A duration of several months is ambitious. You would struggle to keep your participants engaged over such a long period.</li>\n<li>Even if the above weren’t issues, the effort and cost involved would be huge.</li>\n</ul>\n<p>Undaunted, you might choose to balance validity and achievability in a different way, by using a smaller number of interviews, over a shorter duration, and appealing to traders’ sense of curiosity rather than offering money as an incentive for taking part. It’s more achievable, but you’ve sacrificed some validity in the process.</p>\n<p>Validity can take several forms. When you design a research project, ask yourself whether your approach is:</p>\n<ul>\n<li><strong>Representative:</strong> Is your sample a cross-section of the group you’re interested in? Watch out for the way you recruit and incentivize participants as a source of bias.</li>\n<li><strong>Realistic:</strong> If you’re asking people to complete a task, is it a fair reflection of what they’d do normally? For example, if you’re getting them to assess a smartphone prototype, don’t ask them to try it on a laptop.</li>\n<li><strong>Knowable:</strong> Sometimes people don’t know why they do things. If that’s the case, it’s not valid to ask them! For example, users may not know why they tend to prefer puzzle games to racing games, but they will probably still take a guess.</li>\n<li><strong>Memorable:</strong> Small details are hard to remember. If you’re asking your participants to recall something, like how many times they’ve looked at their email in the past month, they’ll be unlikely to remember, and therefore your question isn’t valid: you need a different approach, such as one based on analytics. If you were to ask them how many times they’ve been to a funeral in the past month, you can put more trust in their answer.</li>\n<li><strong>In the moment:</strong> If your question isn’t knowable or memorable, it’s still possible to tackle it ‘in the moment’. We’ll say more about this below.</li>\n</ul>\n<p>Takeout: You want your research approach to be as valid as possible (ie, representative and realistic, as well as focused on questions that are knowable and memorable) within the constraints of achievability. Normally, achievability is a matter of time and budget, which leads us to…</p>\n<h3 id=\"scaling-your-investment\">Scaling Your Investment</h3>\n<p>Imagine you were considering changing a paragraph of text on your website. In theory, you could conduct a six-month contextual research project at vast expense, but it probably wouldn’t be worth it. The scale of investment wouldn’t be justified by the value of the change.</p>\n","protected":false},"author":72597,"featured_media":161143,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[6131,8603,412],"tags":[9506,11007,1097],"_links":{"self":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/posts/160926"}],"collection":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/posts"}],"about":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/types/post"}],"author":[{"embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/users/72597"}],"replies":[{"embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/comments?post=160926"}],"version-history":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/posts/160926/revisions"}],"wp_featuredmedia":[{"embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/media/161143"}],"wp_attachment":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/media?parent=160926"}],"wp_term":[{"taxonomy":"category","embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/categories?post=160926"},{"taxonomy":"post_tag","embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/tags?post=160926"}],"curies":[{"name":"wp","href":"https://api.w.org/{rel}","templated":true}]}}
{"index":{"_index":"blogs","_id":160904,"_type":"default"}}
{"id":160904,"date":"2017-10-28T09:00:36","date_gmt":"2017-10-28T16:00:36","guid":{"rendered":"https://www.sitepoint.com/?p=160904"},"modified":"2017-10-26T20:37:55","modified_gmt":"2017-10-27T03:37:55","slug":"how-to-make-paper-prototypes","status":"publish","type":"post","link":"https://www.sitepoint.com/how-to-make-paper-prototypes/","title":{"rendered":"How to Make Paper Prototypes"},"content":{"rendered":"<p><em>The following is a short extract from our book, <a href=\"https://www.sitepoint.com/premium/books/designing-ux-prototyping\">Designing UX: Prototyping</a>, written by Dan Goodwin and Ben Coleman. It’s the ultimate guide to prototyping. SitePoint Premium members get access with their membership, or you can buy a copy in stores worldwide.</em></p>\n<p>There are no rules for making paper prototypes––that is what's great about it. You need materials that are commonly found in any home or office, but if you have to buy them, they are relatively inexpensive.</p>\n<h2 id=\"what-you-ll-need\">What You'll Need</h2>\n<p>At the very least you'll require paper and a pen––this low barrier to entry is one of the best aspects about this approach. For more complex and interactive prototypes, though, you'll need a bigger arsenal, and if you're running workshops or doing a lot of prototyping, assembling a toolkit of the following items is a good idea.</p>\n<p>We'd suggest the following items when undertaking a prototyping session:</p>\n<ul>\n<li>paper with a grid or dot grid (preferred)</li>\n<li>sticky notes (never leave home without them!)</li>\n<li>pencils</li>\n<li>eraser</li>\n<li>pens (Sharpies in different colors and thicknesses are ideal)</li>\n<li>scissors or craft knife</li>\n<li>glue (preferably restickable)</li>\n</ul>\n<p>Items that are nice to have include:</p>\n<ul>\n<li>index cards</li>\n<li>mounting putty</li>\n<li>adhesive tape (preferably removable to move items around)</li>\n<li>highlighter pens</li>\n<li>double-ended marker pens with fine and normal nibs </li>\n<li>transparent sheets and markers</li>\n<li>a box for filing or transporting your prototype</li>\n</ul>\n<p>We’ll look at the possibilities involved in using different materials later in the chapter.</p>\n<h3 id=\"your-approach\">Your Approach</h3>\n<p>Strictly speaking, you could just dive in and start making; however, a process we’ve found helpful at fffunction is to think outward-in, focusing on increasingly smaller pieces as you go, such as:</p>\n<ol>\n<li>devices</li>\n<li>screens</li>\n<li>elements</li>\n<li>interactivity or state changes</li>\n</ol>\n<h3 id=\"devices\">Devices</h3>\n<p>What size viewport or device are we designing for in this instance? Any available user research may inform this. Analytics data will indicate what an existing audience may prefer to use. A goal of the design work could be to prototype an improved experience on small-screen devices.</p>\n<h4>Desktop or Laptop</h4>\n<p>An A4- or US letter-sized piece of paper is suitable here, where you could use different orientations to mimic the device, such as landscape for a desktop or laptop. If you want a more realistic source, you could print out a browser frame graphic.</p>\n<h4>Tablet</h4>\n<p>A5- or US half-letter-sized paper should suffice, although if you're designing for a large tablet such as the Apple iPad Pro (12.9 inches), you might want to stick with the A4/Letter size. Again, you can choose an orientation depending on what you expect the user to have. If you want to make this more realistic, creating a dummy device is an option. The most lo-fi approach would be to draw it on a piece of card and cut out a hole where the screen would be, as depicted below.</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508506713cardboard-ipad.jpg\" alt=\"\" width=\"600\" height=\"450\" class=\"aligncenter size-full wp-image-160908\" /></p>\n<p>Laser-cut and 3D-printed devices have been created specifically to help use paper prototypes in a more natural way, allowing the prototype to be part of a device.</p>\n<h4>Phone</h4>\n<p>As with the previous examples, you can sketch directly onto paper: A5- or US half-letter-sized, index cards, or sticky notes, and use different orientations. There are more options available for mobile devices, though, than any other form.</p>\n<p>You could make a cellphone border with a cutout window for the screen, or use cards laid on top of the device to act as different screens. </p>\n<p>As mentioned, there are also laser-cut and 3D-printed device models available. The figure below shows a laser-cut plywood phone model that we use in our work.</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508506743laser-cut-devices.jpg\" alt=\"\" width=\"600\" height=\"391\" class=\"aligncenter size-full wp-image-160909\" /></p>\n<p>Plastic or card model devices with a channel to insert pieces of paper to simulate scrolling are also available. You could even place all the screens on a long piece of paper and slide it around to simulate navigation.</p>\n<p>Another option is to use a small spiral-bound notebook to flick between screens, with tabs or colored dots forming navigation elements, as seen below. This is a nice approach as it mimics how people use their cellphone: held in one hand while the other taps it to interact. </p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508506769notebook-prototype.jpg\" alt=\"\" width=\"600\" height=\"294\" class=\"aligncenter size-full wp-image-160910\" /></p>\n<h3 id=\"screens\">Screens</h3>\n<p>Now we'll define what screens are required to communicate the design. It’s helpful to consider what steps in the journey the user will take. We can develop a list from existing work such as user journeys, task models, sitemaps, information architecture, or a functional specification. Some of this was covered in the <a href=\"#gather-resources\"><em>Gather Resources</em></a> section of Chapter 2, to which you can refer back if you need a refresher. Once you've developed a list, you can start to think about what elements will be required for each screen.</p>\n<p>If you don't know the screen size, or have an incomplete picture of what you are designing, sketching the steps out on cards can be useful for working a product at a high level before going into more detail. We'd recommend beginning<br />\n with smaller A5 or index cards to help you focus on the individual interactions on each screen; aiming for one purpose per screen is a good way to start. You can then arrange them on a table to experiment with different flows through a process.</p>\n<h3 id=\"elements\">Elements</h3>\n<p>When looking at the elements that make up your screen, consider how users will interact with them during the prototype process. What needs to happen when they touch that element?</p>\n<p>In some cases, you may have a consistent interface with only one window changing based on interactions around it. A simple example would be a menu in a left-hand column that changes the content of the right-hand column. This could be represented with the same card on the left, and separate cards for each piece of interchangeable content on the right, as shown below.</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508506803frame-layers.jpg\" alt=\"\" width=\"600\" height=\"450\" class=\"aligncenter size-full wp-image-160911\" /></p>\n<h3 id=\"interactivity\">Interactivity</h3>\n<p>All the elements you've established will each be interactive at various points. There’s a challenge here in how to replicate that functionality with paper. Again, there’s likely to be no “right first time” solution to this so it’s worth experimenting with different materials and approaches.</p>\n<h5>Scrolling and sliding</h5>\n<p>One approach we’ve used is to cut parts out of the screen and then threading strips of paper through to enable sliding and scrolling elements. A 1–2 mm hole is large enough to slip paper through and enable the right amount of clearance for “scrolling.” The figure below depicts a paper vertical scrolling device.</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508506823sliders-scrolling-vertical.jpg\" alt=\"\" width=\"600\" height=\"450\" class=\"aligncenter size-full wp-image-160912\" /> </p>\n<p>Another approach is to use a more advanced device model with a slot to slide paper through indicating a horizontal scroll.</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508506857sliders-scrolling-horizontal.jpg\" alt=\"\" width=\"600\" height=\"450\" class=\"aligncenter size-full wp-image-160913\" /></p>\n<h4>Menus</h4>\n<p>For a menu, pieces of paper can be placed into position on an interaction, or, similarly, you could use sticky notes so that they hold their position but are easy to move.</p>\n<p>If you’re using a cutout device, the menu could be positioned off the canvas or out of sight, then slid in to be revealed as depicted below.</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508507024off-canvas-menu.jpg\" alt=\"off-canvas menu\" width=\"600\" height=\"450\" class=\"aligncenter size-full wp-image-160914\" /> </p>\n<h4>Messages and Pop-up Boxes</h4>\n<p>Sticky notes are handy for messages, popups, or tooltips as they can be placed on the screen and then removed following an interaction or after a period of time. You can purchase them in smaller sizes, even speech bubble shapes that are perfectly suited to this as shown below.</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508507054tooltip.jpg\" alt=\"Sticky note speech bubbles are ideal for messages or popups\" width=\"600\" height=\"600\" class=\"aligncenter size-full wp-image-160915\" /></p>\n<h4>Tabs</h4>\n<p>You can either create your own tabs by cutting them out of paper, or buying index cards. When selecting another tab, shuffle through the deck of tab cards and arrange the selected tab on top.<br />\n<img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508507078tabs.jpg\" alt=\"Paper or index cards easily substitute for tabs\" width=\"600\" height=\"294\" class=\"aligncenter size-full wp-image-160916\" /><br />\n> </p>\n<h4>Accordions</h4>\n</p>\n<p>Now's the time for a little origami. Draw the accordion content with everything in view on the page. Starting at the top, fold up the accordion so that just the titles are visible and the drawer content is hidden. Then, when you tap on a title, you can reveal the folded piece of content. The figure below presents this process.</p>\n<p>If you'd prefer to skip the folding you could make individual pieces, or use sticky notes for the sections that will be revealed.</p>\n<p> <img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508507107accordions.jpg\" alt=\"Bending it like ... an accordion\" width=\"600\" height=\"392\" class=\"aligncenter size-full wp-image-160917\" /></p>\n<p>A common responsive design pattern is to interchange an accordion style menu on smaller screens with tabs on larger screens. You can see this prototyped as two distinct elements in the figure below.</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508507130tabs-accordion.jpg\" alt=\"Accordion and tabs as part of a responsive design pattern\" width=\"500\" height=\"500\" class=\"aligncenter size-full wp-image-160918\" /></p>\n<h4>Slide Up / Down Reveals</h4>\n<p>The techniques that we’ve already covered can be employed here. You could elect to hide the content off canvas, or slide it in to view from a slit in the paper. Or you could simply place the content on a separate card and lay it into place when required.</p>\n<h4>Select Boxes</h4>\n<p>Sticky notes work well here to depict a moveable list of items that you would see in a select element, as shown below. The user will be able to see the choices and select one, at which point you can remove the list from the prototype. </p>\n<p> <img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508507157select.jpg\" alt=\"A select box using a sticky note for a drop-down menu\" width=\"600\" height=\"294\" class=\"aligncenter size-full wp-image-160919\" /></p>\n<h4>Checkboxes and Radio Buttons</h4>\n<p>Simply drawing these often suffices for a prototype. You could go as far as to place checked versions on top of the unchecked version following an interaction.</p>\n<p>If part of the purpose of the prototype is to experiment with the positioning of elements on a page, a strip cut of a sticky-note would work.</p>\n<p>You have to weigh up the complexity of building and operating this element in a test scenario against the benefits of having the detail. Make it too fiddly and operating your prototype will become difficult.</p>\n<h4>iOS / Android Native Design Elements</h4>\n<p>There's the option of adding complicated design elements from iOS or Android that could be tricky to replicate or take time to sketch. For example, to reproduce a calendar, it’s simpler to take a screenshot of one from a device, then print and cut it out, rather than sketch it.</p>\n<p>You could elaborate on this and print out a stencil or toolkit library for a device, should you think it will speed up the process and not make the design too prescriptive.</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508507186native-elements.jpg\" alt=\"Native elements\" width=\"803\" height=\"870\" class=\"aligncenter size-full wp-image-160920\" /> </p>\n<h4>Literally <em>Anything</em></h4>\n<p>The aforementioned examples are common design elements that can be found on a standard website, tablet, or phone, but there’s no reason to be constrained by what you've seen before. As has been mentioned, one of the pros of paper prototyping is that you're not bound by the constraints of a digital medium. If you can imagine it, you can probably make it out of paper and prototype with it.</p>\n<h2 id=\"drawing-tips\">Drawing Tips</h2>\n<p>When creating paper prototypes, you'll need to draw elements to make up your sketches. In some circumstances, you may not have to spell out content or be particularly detailed about the elements you're laying onto the page. This could be because you're focusing the interaction on a certain module or element, and want to avoid any distraction with other elements.</p>\n<p>In this scenario, you can utilize a sketching shorthand to represent common elements. As depicted below, titles can be wavy lines, paragraph text with straight lines, and images boxes with diagonal lines across them as you would see in a wireframe.</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508507226sketching-tips-shorthand.jpg\" alt=\"Sketching shorthand tips for paper prototypes\" width=\"600\" height=\"586\" class=\"aligncenter size-full wp-image-160921\" /></p>\n<p>Of course this ignores another pro of using paper prototyping compared to wireframes. Wireframes use a box with diagonal lines to represent an image. You might label a box to indicate what it is, but unless you add an image, your communication is fairly limited. In sketching, you can explore further and sketch the actual content of the image. In the figure below we're introducing a new product by sketching a hero image with two customers using the product. This provides the user with a rough approximation of the experience with the final design.</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508507259sketching-tips-hero.jpg\" alt=\"A hero image sketch showing customers using the product\" width=\"600\" height=\"519\" class=\"aligncenter size-full wp-image-160922\" /></p>\n","protected":false},"excerpt":{"rendered":"<p><em>The following is a short extract from our book, <a href=\"https://www.sitepoint.com/premium/books/designing-ux-prototyping\">Designing UX: Prototyping</a>, written by Dan Goodwin and Ben Coleman. It’s the ultimate guide to prototyping. SitePoint Premium members get access with their membership, or you can buy a copy in stores worldwide.</em></p>\n<p>There are no rules for making paper prototypes––that is what's great about it. You need materials that are commonly found in any home or office, but if you have to buy them, they are relatively inexpensive.</p>\n<h2 id=\"what-you-ll-need\">What You'll Need</h2>\n<p>At the very least you'll require paper and a pen––this low barrier to entry is one of the best aspects about this approach. For more complex and interactive prototypes, though, you'll need a bigger arsenal, and if you're running workshops or doing a lot of prototyping, assembling a toolkit of the following items is a good idea.</p>\n<p>We'd suggest the following items when undertaking a prototyping session:</p>\n<ul>\n<li>paper with a grid or dot grid (preferred)</li>\n<li>sticky notes (never leave home without them!)</li>\n<li>pencils</li>\n<li>eraser</li>\n<li>pens (Sharpies in different colors and thicknesses are ideal)</li>\n<li>scissors or craft knife</li>\n<li>glue (preferably restickable)</li>\n</ul>\n<p>Items that are nice to have include:</p>\n<ul>\n<li>index cards</li>\n<li>mounting putty</li>\n<li>adhesive tape (preferably removable to move items around)</li>\n<li>highlighter pens</li>\n<li>double-ended marker pens with fine and normal nibs </li>\n<li>transparent sheets and markers</li>\n<li>a box for filing or transporting your prototype</li>\n</ul>\n<p>We’ll look at the possibilities involved in using different materials later in the chapter.</p>\n<h3 id=\"your-approach\">Your Approach</h3>\n<p>Strictly speaking, you could just dive in and start making; however, a process we’ve found helpful at fffunction is to think outward-in, focusing on increasingly smaller pieces as you go, such as:</p>\n<ol>\n<li>devices</li>\n<li>screens</li>\n<li>elements</li>\n<li>interactivity or state changes</li>\n</ol>\n<h3 id=\"devices\">Devices</h3>\n<p>What size viewport or device are we designing for in this instance? Any available user research may inform this. Analytics data will indicate what an existing audience may prefer to use. A goal of the design work could be to prototype an improved experience on small-screen devices.</p>\n<h4>Desktop or Laptop</h4>\n<p>An A4- or US letter-sized piece of paper is suitable here, where you could use different orientations to mimic the device, such as landscape for a desktop or laptop. If you want a more realistic source, you could print out a browser frame graphic.</p>\n<h4>Tablet</h4>\n<p>A5- or US half-letter-sized paper should suffice, although if you're designing for a large tablet such as the Apple iPad Pro (12.9 inches), you might want to stick with the A4/Letter size. Again, you can choose an orientation depending on what you expect the user to have. If you want to make this more realistic, creating a dummy device is an option. The most lo-fi approach would be to draw it on a piece of card and cut out a hole where the screen would be, as depicted below.</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508506713cardboard-ipad.jpg\" alt=\"\" width=\"600\" height=\"450\" class=\"aligncenter size-full wp-image-160908\" /></p>\n<p>Laser-cut and 3D-printed devices have been created specifically to help use paper prototypes in a more natural way, allowing the prototype to be part of a device.</p>\n<h4>Phone</h4>\n<p>As with the previous examples, you can sketch directly onto paper: A5- or US half-letter-sized, index cards, or sticky notes, and use different orientations. There are more options available for mobile devices, though, than any other form.</p>\n<p>You could make a cellphone border with a cutout window for the screen, or use cards laid on top of the device to act as different screens. </p>\n<p>As mentioned, there are also laser-cut and 3D-printed device models available. The figure below shows a laser-cut plywood phone model that we use in our work.</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508506743laser-cut-devices.jpg\" alt=\"\" width=\"600\" height=\"391\" class=\"aligncenter size-full wp-image-160909\" /></p>\n<p>Plastic or card model devices with a channel to insert pieces of paper to simulate scrolling are also available. You could even place all the screens on a long piece of paper and slide it around to simulate navigation.</p>\n<p>Another option is to use a small spiral-bound notebook to flick between screens, with tabs or colored dots forming navigation elements, as seen below. This is a nice approach as it mimics how people use their cellphone: held in one hand while the other taps it to interact. </p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508506769notebook-prototype.jpg\" alt=\"\" width=\"600\" height=\"294\" class=\"aligncenter size-full wp-image-160910\" /></p>\n<h3 id=\"screens\">Screens</h3>\n<p>Now we'll define what screens are required to communicate the design. It’s helpful to consider what steps in the journey the user will take. We can develop a list from existing work such as user journeys, task models, sitemaps, information architecture, or a functional specification. Some of this was covered in the <a href=\"#gather-resources\"><em>Gather Resources</em></a> section of Chapter 2, to which you can refer back if you need a refresher. Once you've developed a list, you can start to think about what elements will be required for each screen.</p>\n<p>If you don't know the screen size, or have an incomplete picture of what you are designing, sketching the steps out on cards can be useful for working a product at a high level before going into more detail. We'd recommend beginning<br />\n with smaller A5 or index cards to help you focus on the individual interactions on each screen; aiming for one purpose per screen is a good way to start. You can then arrange them on a table to experiment with different flows through a process.</p>\n<h3 id=\"elements\">Elements</h3>\n<p>When looking at the elements that make up your screen, consider how users will interact with them during the prototype process. What needs to happen when they touch that element?</p>\n<p>In some cases, you may have a consistent interface with only one window changing based on interactions around it. A simple example would be a menu in a left-hand column that changes the content of the right-hand column. This could be represented with the same card on the left, and separate cards for each piece of interchangeable content on the right, as shown below.</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508506803frame-layers.jpg\" alt=\"\" width=\"600\" height=\"450\" class=\"aligncenter size-full wp-image-160911\" /></p>\n<h3 id=\"interactivity\">Interactivity</h3>\n<p>All the elements you've established will each be interactive at various points. There’s a challenge here in how to replicate that functionality with paper. Again, there’s likely to be no “right first time” solution to this so it’s worth experimenting with different materials and approaches.</p>\n","protected":false},"author":72598,"featured_media":161140,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[6131,8760,8005,412,8601],"tags":[1954,9797,1097],"_links":{"self":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/posts/160904"}],"collection":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/posts"}],"about":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/types/post"}],"author":[{"embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/users/72598"}],"replies":[{"embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/comments?post=160904"}],"version-history":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/posts/160904/revisions"}],"wp_featuredmedia":[{"embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/media/161140"}],"wp_attachment":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/media?parent=160904"}],"wp_term":[{"taxonomy":"category","embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/categories?post=160904"},{"taxonomy":"post_tag","embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/tags?post=160904"}],"curies":[{"name":"wp","href":"https://api.w.org/{rel}","templated":true}]}}
{"index":{"_index":"blogs","_id":161162,"_type":"default"}}
{"id":161162,"date":"2017-10-27T16:09:30","date_gmt":"2017-10-27T23:09:30","guid":{"rendered":"https://www.sitepoint.com/?p=161162"},"modified":"2017-10-27T16:09:30","modified_gmt":"2017-10-27T23:09:30","slug":"angular-forms","status":"publish","type":"post","link":"https://www.sitepoint.com/angular-forms/","title":{"rendered":"Quickly Create Simple yet Powerful Angular Forms"},"content":{"rendered":"<p class=\"wp-special\">Forms are an essential part of many web applications, being the most common way to enter and edit text-based data. Front-end JavaScript frameworks such as <a href=\"https://angular.io/\">Angular</a>, often have their own idiomatic ways of creating and validating forms that you need to get to grips with to be productive.</p>\n\n<p>Angular allows you to streamline this common task by providing two types of forms that you can create:</p>\n<ul>\n<li><strong>Template-driven forms</strong> – simple forms that can be made rather quickly.</li>\n<li><strong>Reactive forms</strong> – more complex forms that give you greater control over the elements in the form.</li>\n</ul>\n<p>In this article, we’ll make a simple example form with each method to see how it’s done.</p>\n<h2 id=\"prerequisites\">Prerequisites</h2>\n<p>You do not need to know all the details of how to create an Angular application to understand the framework’s usefulness when it comes to forms. However, if you want to get a better grasp of Angular, you can take a look at this SitePoint article series on <a href=\"https://www.sitepoint.com/angular-2-tutorial/\">building a CRUD app with Angular</a>.</p>\n<h2 id=\"requirements\">Requirements</h2>\n<p>We will use <a href=\"http://getbootstrap.com/\">Bootstrap</a> in this tutorial. It is not an integral part of an Angular application, but it will help us streamline our efforts even further by providing ready-made styles.</p>\n<p>This is how you can add it to your application:</p>\n<ol>\n<li>\n<p>Open the command prompt and navigate to the folder of your project</p>\n</li>\n<li>\n<p>Type <code>npm install bootstrap@next</code>. This will add the latest version of bootstrap to the project</p>\n</li>\n<li>\n<p>Edit the <code>.angular-cli.json</code> file and add a link to the Bootstrap CSS file</p>\n<pre><code class=\"javascript language-javascript\">\"apps\": [\r\n\"styles\": [\r\n \"../node_modules/bootstrap/dist/css/bootstrap.css\"\r\n ]\r\n] \r\n</code></pre>\n<p>We will not use the Bootstrap JavaScript file in this application.</p>\n</li>\n<li>\n<p>Both template-driven Forms and Reactive Forms require the <code>FormsModule</code>. It should be added to the application in <code>app.module</code>:</p>\n<pre><code class=\"typescript language-typescript\">import { FormsModule } from '@angular/forms';\r\n@NgModule({\r\nimports: [\r\n BrowserModule,\r\n FormsModule\r\n]\r\n})\r\n</code></pre>\n</li>\n</ol>\n<p>With that out of the way, we can proceed with the forms themselves.</p>\n<h2 id=\"templatedrivenforms\">Template-Driven Forms</h2>\n<p>Let us assume you want to create a simple form as quickly as possible. For example, you need a company registration form. How can you create the form?</p>\n<p>The first step is to create the <code><form></code> tag in your view. </p>\n<pre><code class=\"markup language-markup\"><form #companyForm=\"ngForm\">\r\n</code></pre>\n<p>We need to modify this tag in two ways in order to submit the form and use the information from the input fields in our component:</p>\n<ul>\n<li>We will declare a template variable using the <code>ngForm</code> directive.</li>\n<li>We will bind the <code>ngSubmit</code> event to a method we will create in our component</li>\n</ul>\n<pre><code class=\"markup language-markup\"><form #companyForm=\"ngForm\" (ngSubmit)=\"submitCompany(companyForm.form);\">\r\n</code></pre>\n<p>We will create the <code>submitCompany</code> method in the component a bit later. It will be called when the form is submitted and we will pass it the data from the form via <code>companyForm.form</code>. </p>\n<p>We also need a submit button, regardless of the content of the form. We will use a few Bootstrap classes to style the button. It is good practice to disable the button before all the data validation requirements are met. We can use the template variable we created for the form to achieve this. We will bind the disabled property to the valid property of the <code>companyForm</code> object. This way the button will be disabled if the form is not valid.</p>\n<pre><code class=\"markup language-markup\"><button class=\"btn btn-primary\" [disabled]=\"!companyForm.valid\">Submit</button>\r\n</code></pre>\n<p>Let us assume our simple form will have two fields – an input field for the name of the company and a drop-down field for the company’s industry. </p>\n<h3 id=\"creatingforminputs\">Creating form inputs</h3>\n<p>First, we create an input field for the name:</p>\n<pre><code class=\"markup language-markup\"><input type=\"text\" \r\n class=\"form-control\" \r\n name=\"company-name\">\r\n</code></pre>\n<p>Right now we have a standard input with the type, name and class attributes. What do we need to do to use the Angular approach on our input?</p>\n<p>We need to apply the <code>ngModel</code> directive to it. Angular will create a control object and associate it with the field. Essentially, Angular does some of the work for you behind the scenes. </p>\n<p>This is a good time to mention that <code>ngModel</code> requires the input field to have a name or the form control must be defined as standalone in <code>ngModelOptions</code>. This is not a problem because our form already has a name. Angular will use the name attribute to distinguish between the control objects. </p>\n<p>In addition, we should specify a template variable for the input: <code>#nameField</code> in this case. Angular will set <code>nameField</code> to the <code>ngModel</code> directive that is applied to the input field. We will use this later for the input field’s validation. This variable will also allow us to perform an action based on the value of the field while we are typing in it. </p>\n<p>Now our input looks like this:</p>\n<pre><code class=\"markup language-markup\"><input type=\"text\" \r\n class=\"form-control\" \r\n name=\"company-name\"\r\n ngModel\r\n #nameField=\"ngModel\">\r\n</code></pre>\n<p>It is almost the same, but with a few key changes. </p>\n<h3 id=\"validation\">Validation</h3>\n<p>Let us assume we want the company name field to be required and to have a minimum length of 3 characters. This means we have to add the <code>required</code> and <code>minlength</code> attributes to our input:</p>\n<pre><code class=\"markup language-markup\"><input type=\"text\" \r\n class=\"form-control\" \r\n name=\"company-name\"\r\n ngModel\r\n #nameField=\"ngModel\"\r\n required\r\n minlength=\"3\">\r\n</code></pre>\n<p>Sounds simple enough, right? We will also need to display an error message if any of these two requirements are not met. Angular allows us to check the input’s value and display the appropriate error message before the form is submitted. </p>\n<p>We can perform such a check while the user is typing in the form. First of all, it is a good idea to display an error only after the user has started to interact with the form. There is no use in displaying an error message right after we load the page. This is why we will insert all the error messages for this input inside the following div:</p>\n<pre><code class=\"markup language-markup\"><div *ngIf=\"nameField.touched && nameField.errors\"></div>\r\n</code></pre>\n<p>The <code>ngIf</code> directive allows us to show the div only when a specific condition is true. We will use the <code>nameField</code> template variable again here because it is associated with the input. In our case, the div will be visible only, if the input has been touched and there is a problem with it. Alright, what about the error messages themselves?</p>\n<p>We will place another div inside the aforementioned one for each error message we want. We will create a new div for the error message and use the <code>nameField</code> template variable again:</p>\n<pre><code class=\"markup language-markup\"><div class=\"alert alert-danger\" \r\n *ngIf=\"nameField.errors.required\">\r\n The company name is required\r\n</div>\r\n</code></pre>\n<p>We are using the “alert alert-danger” bootstrap classes to style the text field. The <code>nameField</code> variable has the property <code>errors</code>, which contains an object with key-value pairs for all the current errors. The <code>ngIf</code> directive allows us to show this error message only when the ‘required’ condition is not met. We will use the same approach for the error message about the minimum length.</p>\n<pre><code class=\"markup language-markup\"><div class=\"alert alert-danger\" \r\n *ngIf=\"nameField.errors.minlength\">\r\n The company name should be at least 3 characters long\r\n</div>\r\n</code></pre>\n<p>This div will be visible only when the <code>minlength</code> requirements are not met. here we can make the error message a little bit more dynamic. </p>\n<p>Currently, we have specified the minimum length in two locations – in the input’s attribute and the text field. We can improve this by replacing the hardcoded “3” with the <code>requiredLength</code> property of the <code>minlength</code> object like so: </p>\n<pre><code class=\"markup language-markup\"><div class=\"alert alert-danger\" \r\n *ngIf=\"nameField.errors.minlength\">\r\n The company name should be at least {{ nameField.errors.minlength.requiredLength }} characters long\r\n</div>\r\n</code></pre>\n<p>This way the number of the minimum length in the error message will depend on the input’s <code>minlength</code> attribute. </p>\n<p>Now, we will do the same thing with the dropdown field for the company ‘s industry:</p>\n<pre><code class=\"markup language-markup\"><select class=\"form-control\" \r\n name=\"company-industry\"\r\n ngModel\r\n #industryField=\"ngModel\"\r\n required>\r\n</code></pre>\n<p>We will create a list of the options for the dropdown in the component associated with this view in order to avoid hard-coding values in the HTML.</p>\n<pre><code class=\"typescript language-typescript\">export class ContactFormComponent implements OnInit {\r\n industries = [\r\n {id: 1, name: \"Agriculture\"},\r\n {id: 2, name: \"Manufacturing\"},\r\n {id: 3, name: \"Energy\"},\r\n {id: 4, name: \"Transportation\"},\r\n {id: 5, name: \"Finance\"}\r\n ];\r\n}\r\n</code></pre>\n<p>Now we can list all the options in the view via the <code>ngFor</code> directive. It will create an option tag for every element in the <code>industries</code> array from the component.</p>\n<pre><code class=\"markup language-markup\"><option *ngFor=\"let industry of industries\" \r\n [value]=\"industry.id\">\r\n {{ industry.name }}\r\n</option> \r\n</code></pre>\n<p>The validation for this field is quite easy and similar to that for the company name field:</p>\n<pre><code class=\"markup language-markup\"><div class=\"alert alert-danger\" \r\n *ngIf=\"industryField.touched && !industryField.valid\">\r\n The industry is required\r\n</div>\r\n</code></pre>\n<p>Now our form is ready for submission. Earlier we bound the <code>ngSubmit</code> event to a method called <code>submitCompany</code>; let’s go to the component and add that now:</p>\n<pre><code class=\"typescript language-typescript\">export class ContactFormComponent implements OnInit {\r\n submitCompany(form){\r\n console.log(form.value);\r\n alert(\"The form was submitted\");\r\n form.reset();\r\n }\r\n}\r\n</code></pre>\n<p>The <code>form</code> parameter will contain all the data from the form. On the other hand, <code>form.value</code> will contain just an object with the values of the fields in the form. </p>\n<p>Here I will just log the result in the console, but you can do whatever you want with it. I have added an alert with a message to inform the user the form was submitted. This is not required, but it is a good practice to show some sort of notification. <code>form.reset()</code> will reset the form to its initial state after submission, which means the fields will be emptied.</p>\n<p>Alright let us see what our form should look like:<br />\nhttps://sitepoint-editors.github.io/company-registration-form/</p>\n<h2 id=\"reactiveforms\">Reactive Forms</h2>\n<p>The other kind of form you can create is a reactive form, which allows you to explicitly create control objects for the form fields yourself. This approach is a good choice when you are building a more complex form and you want to have more control over its behavior.</p>\n<p>Let us assume that we need to create an account registration form, which will have two fields for an email and a password. We will use Bootstrap to style this form as well. </p>\n<p>The first step is to import the <code>ReactiveFormsModule</code> class in <code>app.module</code> because it is necessary for all reactive forms:</p>\n<pre><code class=\"typescript language-typescript\">import { ReactiveFormsModule } from \"@angular/forms\";\r\n\r\n@NgModule({\r\n imports: [\r\n ReactiveFormsModule\r\n ]\r\n})\r\n</code></pre>\n<p>Then, we need to import the <code>FormGroup</code> and <code>FormControl</code> classes in the component for our page in order to explicitly define our control objects:</p>\n<pre><code class=\"typescript language-typescript\">import { FormGroup, FormControl } from \"@angular/forms\";\r\n</code></pre>\n<p>Now we should create an instance of the <code>FormGroup</code> class and specify all the fields in our form. To put it simply, we will list key-value pairs. The keys will be the names of the fields and the values will be the form objects.</p>\n<pre><code class=\"typescript language-typescript\">accountForm = new FormGroup({\r\n email: new FormControl(),\r\n password: new FormControl();\r\n</code></pre>\n<p>Next, we should create the form. We will once again need the <code><form></code> tag. We will add the <code>FormGroup</code> directive to it and associate the HTML form with the <code>accountForm</code> form group object we created in the component:</p>\n<pre><code class=\"markup language-markup\"><form [formGroup]=\"accountForm\"></form>\r\n</code></pre>\n<p>Next, we will create the email input field. We will apply the <code>formControlName</code> directive to it and set it to the corresponding key in the list of controls we created in the components, <code>email</code>. </p>\n<pre><code class=\"markup language-markup\"><input type=\"text\" \r\n class=\"form-control\" \r\n id=\"email\" \r\n formControlName=\"email\">\r\n</code></pre>\n<p>We will do the same for the password field:</p>\n<pre><code class=\"markup language-markup\"><input type=\"text\" \r\n id=\"password\" \r\n class=\"form-control\"\r\n formControlName=\"password\">\r\n</code></pre>\n<h3 id=\"validation-1\">Validation</h3>\n<p>The next step is to add validation to the form. We will not use any HTML attributes like “required” as with the template-driven forms. Instead, we have to assign all the validators when we create the form control objects. </p>\n<p>We will go back to the component where we defined our <code>accountForm</code>. All the validator methods for reactive forms are defined in the <code>Validators</code> class, which we have to import:</p>\n<pre><code class=\"typescript language-typescript\">import { FormGroup, FormControl, Validators } from \"@angular/forms\";\r\n</code></pre>\n<p>Then we will assign the validators to the controls in our controller. The format is the following :</p>\n<pre><code class=\"typescript language-typescript\"> form = new FormGroup({\r\n fieldname: new FormControl(\r\n initial value, \r\n synchronous validators, \r\n asynchronous validators)\r\n });\r\n</code></pre>\n<p>Let us assume that both the email and the password fields will be required. We should also check if the email is valid. In addition, the password should contain at least one uppercase letter, one lowercase letter, and one number. Thus, we will use the <code>required</code> and <code>pattern</code> validators from the <code>Validators</code> class for both fields. We will leave their initial values as an empty string.</p>\n<pre><code class=\"typescript language-typescript\">form = new FormGroup({\r\n email: new FormControl(\"\", \r\n [Validators.required, \r\n Validators.pattern('[a-zA-z0-9_\\.]+@[a-zA-Z]+\\.[a-zA-Z]+')]),\r\n password: new FormControl(\"\", \r\n [Validators.required, \r\n Validators.pattern('^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z]).{8,}$')])\r\n });\r\n</code></pre>\n<p>Now we need to go to the template and add the validation messages. We will do this in the same way we did it with with the template-driven forms. However, we will access the control objects in a different way. In our component we can define a property that gives us access to the control in the form like so:</p>\n<pre><code class=\"typescript language-typescript\">get email(){\r\n return this.accountForm.get(\"email\");\r\n}\r\n</code></pre>\n<p>We can access this property in our template. This means that instead of writing <code>this.accountForm.get(\"email\")</code> every time we want to specify a validation message, we can use just <code>email</code>. </p>\n<pre><code class=\"markup language-markup\"><div *ngIf=\"email.touched && email.errors\">\r\n <div class=\"alert alert-danger\" *ngIf=\"email.errors.required\">\r\n The email is required\r\n </div>\r\n </div>\r\n <div *ngIf=\"email.errors\">\r\n <div class=\"alert alert-danger\" *ngIf=\"email.errors.pattern\">\r\n The email is not valid\r\n </div>\r\n </div>\r\n</code></pre>\n<p>This way, the message “The email is required” will appear after the user touched the form and left it empty, while the message “The email is not valid” will appear as the user is typing. We can display the validation messages for the password field in the same way.</p>\n<p>Let us move on to submitting our reactive form. Firstly, we can disable the submit button in a similar way to the one we used with the template-driven form:</p>\n<pre><code class=\"markup language-markup\"><button class=\"btn btn-primary\" type=\"submit\" \r\n [disabled]=\"!accountForm.valid\">Sign up</button>\r\n</code></pre>\n<p>We also need to bind the <code>ngSubmit</code> event to a function, which will be called on submit.</p>\n<pre><code class=\"markup language-markup\"><form [formGroup]=\"accountForm\" (ngSubmit)=\"signup()\">\r\n</code></pre>\n<p>Then we need to define that function in the controller:</p>\n<pre><code class=\"typescript language-typescript\">signup(){\r\n console.log(this.accountForm.value);\r\n alert('The form was submitted');\r\n this.accountForm.reset();\r\n}\r\n</code></pre>\n<p>For now, we will show the submitted data in the console. We will clear the form fields after we display a confirmation message.</p>\n<h3 id=\"asynchronousvalidation\">Asynchronous validation</h3>\n<p>It will be great if we can check if the email the user is trying to submit is already in use. We can perform such a check even as the user is typing in if we use an asynchronous validator. </p>\n<p>We will use a fake API for the purposes of this demo – <a href=\"https://jsonplaceholder.typicode.com/\">JSON Placeholder</a>. This is a useful tool for testing an application because it provides various kinds of data. For example, it can provide a list of users with emails, which we will pretend is the list of existing users for our demo application. You can send get and post requests to it just as you would with a real API. </p>\n<p>We will create a service in our application that connects to this JSON API, and attaches an asynchronous validator to the email field. This way, we will be able to check if the email is already in use.</p>\n<p>First, we will create the service. We can do that via the Angular CLI</p>\n<pre><code class=\"bash language-bash\">ng g service server.service\r\n</code></pre>\n<p>Then, we have to add the service to <code>app.module</code> so that we can use it in the application:</p>\n<pre><code class=\"typescript language-typescript\">import { ServerService } from \"./server.service\";\r\n@NgModule({\r\n providers: [\r\n ServerService\r\n ],\r\n bootstrap: [AppComponent]\r\n})\r\n</code></pre>\n<p>In our service, we need to import the <code>Injectable</code>, <code>Http</code> and <code>Observable</code> classes as well as the <code>map</code> and <code>filter</code> RxJS operators. Then we will specify the URL to our test API. After we get the results we will filter them to see if there is a user with an email that matches the one the user typed, which we will pass to it when we perform the request.</p>\n<pre><code class=\"typescript language-typescript\">@Injectable()\r\nexport class ServerService {\r\n private url = \"http://jsonplaceholder.typicode.com/users\";\r\n\r\n constructor(private http: Http) { }\r\n\r\n checkUsers(email: string) {\r\n return this.http\r\n .get(this.url)\r\n .map(res => res.json())\r\n .map(users => users.filter(user => user.email === email))\r\n .map(users => !users.length);\r\n }\r\n}\r\n</code></pre>\n<p>Now we have to create the validator, which will use this service to check the email. We will create a new typescript file, <strong>custom.validators.ts</strong>. This will allow us to separate our code in a more effective way and reuse the validator. There we will import the <code>AbstractControl</code> and <code>ValidationErrors</code> classes as well as the <code>ServerService</code>.</p>\n<pre><code class=\"typescript language-typescript\">import { AbstractControl, ValidationErrors } from '@angular/forms';\r\nimport { ServerService } from './server.service'; \r\n\r\nexport class Customvalidators{\r\n static checkDuplicateEmail(serverService: ServerService) {\r\n return (control: AbstractControl) => {\r\n return serverService.checkUsers(control.value).map(res => {\r\n return res ? null : { duplicateEmail: true };\r\n });\r\n };\r\n }\r\n}\r\n</code></pre>\n<p>We create an instance of our <code>serverService</code> and call the <code>checkUsers</code> method we created in it. Custom validators are supposed to return <code>null</code> if everything is OK, or an object with key-value pairs that describe the error otherwise.</p>\n<p>Now we will go to our component to apply the asynchronous validator to the email field. We will have to import the <code>ServerService</code> into the component as well and create an instance of it in order to perform the request to our test API.</p>\n<pre><code class=\"typescript language-typescript\">import { ServerService } from \"../server.service\";\r\n\r\nconstructor(private serverService: ServerService){\r\n\r\n}\r\n\r\naccountForm = new FormGroup({\r\n email: new FormControl(\"\", synchronous validators, \r\n Customvalidators.checkDuplicateEmail(this.serverService))\r\n});\r\n</code></pre>\n<p>The only thing left to do is add a validation message</p>\n<pre><code class=\"markup language-markup\"><div *ngIf=\"email.errors\">\r\n <div class=\"alert alert-danger\" *ngIf=\"email.errors.duplicateEmail\">\r\n The email is already in use\r\n </div>\r\n</div>\r\n</code></pre>\n<p>Now let’s see what our form looks like.<br />\nhttps://sitepoint-editors.github.io/account-registration-form/</p>\n<h2 id=\"wrappingup\">Wrapping Up</h2>\n<p>As you can see, Angular allows you to do a few neat tricks with forms. Not only can you create simple forms quickly by making them template-driven, but you can also implement complex features in them if you need to.</p>\n","protected":false},"excerpt":{"rendered":"<p class=\"wp-special\">Forms are an essential part of many web applications, being the most common way to enter and edit text-based data. Front-end JavaScript frameworks such as <a href=\"https://angular.io/\">Angular</a>, often have their own idiomatic ways of creating and validating forms that you need to get to grips with to be productive.</p>\n<p>Angular allows you to streamline this common task by providing two types of forms that you can create:</p>\n<ul>\n<li><strong>Template-driven forms</strong> – simple forms that can be made rather quickly.</li>\n<li><strong>Reactive forms</strong> – more complex forms that give you greater control over the elements in the form.</li>\n</ul>\n<p>In this article, we’ll make a simple example form with each method to see how it’s done.</p>\n<h2 id=\"prerequisites\">Prerequisites</h2>\n<p>You do not need to know all the details of how to create an Angular application to understand the framework’s usefulness when it comes to forms. However, if you want to get a better grasp of Angular, you can take a look at this SitePoint article series on <a href=\"https://www.sitepoint.com/angular-2-tutorial/\">building a CRUD app with Angular</a>.</p>\n<h2 id=\"requirements\">Requirements</h2>\n<p>We will use <a href=\"http://getbootstrap.com/\">Bootstrap</a> in this tutorial. It is not an integral part of an Angular application, but it will help us streamline our efforts even further by providing ready-made styles.</p>\n<p>This is how you can add it to your application:</p>\n<ol>\n<li>\n<p>Open the command prompt and navigate to the folder of your project</p>\n</li>\n<li>\n<p>Type <code>npm install bootstrap@next</code>. This will add the latest version of bootstrap to the project</p>\n</li>\n<li>\n<p>Edit the <code>.angular-cli.json</code> file and add a link to the Bootstrap CSS file</p>\n<pre><code class=\"javascript language-javascript\">\"apps\": [\r\n\"styles\": [\r\n \"../node_modules/bootstrap/dist/css/bootstrap.css\"\r\n ]\r\n] \r\n</code></pre>\n<p>We will not use the Bootstrap JavaScript file in this application.</p>\n</li>\n<li>\n<p>Both template-driven Forms and Reactive Forms require the <code>FormsModule</code>. It should be added to the application in <code>app.module</code>:</p>\n<pre><code class=\"typescript language-typescript\">import { FormsModule } from '@angular/forms';\r\n@NgModule({\r\nimports: [\r\n BrowserModule,\r\n FormsModule\r\n]\r\n})\r\n</code></pre>\n</li>\n</ol>\n<p>With that out of the way, we can proceed with the forms themselves.</p>\n<h2 id=\"templatedrivenforms\">Template-Driven Forms</h2>\n<p>Let us assume you want to create a simple form as quickly as possible. For example, you need a company registration form. How can you create the form?</p>\n<p>The first step is to create the <code><form></code> tag in your view. </p>\n<pre><code class=\"markup language-markup\"><form #companyForm=\"ngForm\">\r\n</code></pre>\n<p>We need to modify this tag in two ways in order to submit the form and use the information from the input fields in our component:</p>\n<ul>\n<li>We will declare a template variable using the <code>ngForm</code> directive.</li>\n<li>We will bind the <code>ngSubmit</code> event to a method we will create in our component</li>\n</ul>\n<pre><code class=\"markup language-markup\"><form #companyForm=\"ngForm\" (ngSubmit)=\"submitCompany(companyForm.form);\">\r\n</code></pre>\n<p>We will create the <code>submitCompany</code> method in the component a bit later. It will be called when the form is submitted and we will pass it the data from the form via <code>companyForm.form</code>. </p>\n<p>We also need a submit button, regardless of the content of the form. We will use a few Bootstrap classes to style the button. It is good practice to disable the button before all the data validation requirements are met. We can use the template variable we created for the form to achieve this. We will bind the disabled property to the valid property of the <code>companyForm</code> object. This way the button will be disabled if the form is not valid.</p>\n<pre><code class=\"markup language-markup\"><button class=\"btn btn-primary\" [disabled]=\"!companyForm.valid\">Submit</button>\r\n</code></pre>\n<p>Let us assume our simple form will have two fields – an input field for the name of the company and a drop-down field for the company’s industry. </p>\n<h3 id=\"creatingforminputs\">Creating form inputs</h3>\n<p>First, we create an input field for the name:</p>\n<pre><code class=\"markup language-markup\"><input type=\"text\" \r\n class=\"form-control\" \r\n name=\"company-name\">\r\n</code></pre>\n<p>Right now we have a standard input with the type, name and class attributes. What do we need to do to use the Angular approach on our input?</p>\n<p>We need to apply the <code>ngModel</code> directive to it. Angular will create a control object and associate it with the field. Essentially, Angular does some of the work for you behind the scenes. </p>\n<p>This is a good time to mention that <code>ngModel</code> requires the input field to have a name or the form control must be defined as standalone in <code>ngModelOptions</code>. This is not a problem because our form already has a name. Angular will use the name attribute to distinguish between the control objects. </p>\n<p>In addition, we should specify a template variable for the input: <code>#nameField</code> in this case. Angular will set <code>nameField</code> to the <code>ngModel</code> directive that is applied to the input field. We will use this later for the input field’s validation. This variable will also allow us to perform an action based on the value of the field while we are typing in it. </p>\n<p>Now our input looks like this:</p>\n<pre><code class=\"markup language-markup\"><input type=\"text\" \r\n class=\"form-control\" \r\n name=\"company-name\"\r\n ngModel\r\n #nameField=\"ngModel\">\r\n</code></pre>\n<p>It is almost the same, but with a few key changes. </p>\n<h3 id=\"validation\">Validation</h3>\n<p>Let us assume we want the company name field to be required and to have a minimum length of 3 characters. This means we have to add the <code>required</code> and <code>minlength</code> attributes to our input:</p>\n<pre><code class=\"markup language-markup\"><input type=\"text\" \r\n class=\"form-control\" \r\n name=\"company-name\"\r\n ngModel\r\n #nameField=\"ngModel\"\r\n required\r\n minlength=\"3\">\r\n</code></pre>\n<p>Sounds simple enough, right? We will also need to display an error message if any of these two requirements are not met. Angular allows us to check the input’s value and display the appropriate error message before the form is submitted. </p>\n<p>We can perform such a check while the user is typing in the form. First of all, it is a good idea to display an error only after the user has started to interact with the form. There is no use in displaying an error message right after we load the page. This is why we will insert all the error messages for this input inside the following div:</p>\n<pre><code class=\"markup language-markup\"><div *ngIf=\"nameField.touched && nameField.errors\"></div>\r\n</code></pre>\n<p>The <code>ngIf</code> directive allows us to show the div only when a specific condition is true. We will use the <code>nameField</code> template variable again here because it is associated with the input. In our case, the div will be visible only, if the input has been touched and there is a problem with it. Alright, what about the error messages themselves?</p>\n<p>We will place another div inside the aforementioned one for each error message we want. We will create a new div for the error message and use the <code>nameField</code> template variable again:</p>\n<pre><code class=\"markup language-markup\"><div class=\"alert alert-danger\" \r\n *ngIf=\"nameField.errors.required\">\r\n The company name is required\r\n</div>\r\n</code></pre>\n<p>We are using the “alert alert-danger” bootstrap classes to style the text field. The <code>nameField</code> variable has the property <code>errors</code>, which contains an object with key-value pairs for all the current errors. The <code>ngIf</code> directive allows us to show this error message only when the ‘required’ condition is not met. We will use the same approach for the error message about the minimum length.</p>\n","protected":false},"author":72603,"featured_media":161163,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[768,407],"tags":[6152,16,9543],"_links":{"self":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/posts/161162"}],"collection":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/posts"}],"about":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/types/post"}],"author":[{"embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/users/72603"}],"replies":[{"embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/comments?post=161162"}],"version-history":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/posts/161162/revisions"}],"wp_featuredmedia":[{"embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/media/161163"}],"wp_attachment":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/media?parent=161162"}],"wp_term":[{"taxonomy":"category","embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/categories?post=161162"},{"taxonomy":"post_tag","embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/tags?post=161162"}],"curies":[{"name":"wp","href":"https://api.w.org/{rel}","templated":true}]}}
{"index":{"_index":"blogs","_id":160893,"_type":"default"}}
{"id":160893,"date":"2017-10-27T10:00:21","date_gmt":"2017-10-27T17:00:21","guid":{"rendered":"https://www.sitepoint.com/?p=160893"},"modified":"2017-10-26T20:35:40","modified_gmt":"2017-10-27T03:35:40","slug":"how-to-prototype-interactions-with-adobe-xd","status":"publish","type":"post","link":"https://www.sitepoint.com/how-to-prototype-interactions-with-adobe-xd/","title":{"rendered":"How to Prototype Interactions with Adobe XD"},"content":{"rendered":"<p><em>The following is a short extract from our book, <a href=\"https://www.sitepoint.com/premium/books/jump-start-adobe-xd\">Jump Start Adobe XD</a>, written by Daniel Schwarz, a highly practical tutorial on this fantastic prototyping tool. SitePoint Premium members get access with their membership, or you can buy a copy in stores worldwide.</em></p>\n<h2 id=\"prototyping-interactions\">Prototyping Interactions</h2>\n<p>Let's start by linking the welcome screen to the location filter screen, effectively demonstrating a user flow where the user searches for a type of cuisine, and is then asked to specify <em>where</em> they’d like to eat in the location filter screen. Click on the right arrow icon (inside the input field on the welcome screen), where a blue arrow-tab will appear alongside it.</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508493517start-flow.png\" alt=\"Creating a user flow\" width=\"978\" height=\"695\" class=\"aligncenter size-full wp-image-160894\" /></p>\n<p>Drag and drop this blue tab into the location filter screen. A user flow will have been created, and a small modal will appear where you can specify transition settings for this user flow – that is, how the screen will transition into the next one (the type of animation effect, the duration of that animation, etc).</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508493549flow-done.png\" alt=\"Flow and transition settings\" width=\"993\" height=\"608\" class=\"aligncenter size-full wp-image-160895\" /></p>\n<p>Later on (when we learn how to preview/test our prototypes), we’ll be able to literally click on this icon and be taken to the next screen, as if we were using a real app — this is how we (and our developers, and <em>maybe</em> even our clients) use the prototype workspace to test our concept before committing to it.</p>\n<p>Next, we’ll specify the transition settings for this user flow.</p>\n<h3 id=\"designing-transitions\">Designing Transitions</h3>\n<p>Animation comes with its own set of UX challenges. A slow transition can make the user feel like your app is taking too long, whereas a transition that’s too fast can leave the user wondering what even happened. And then there’s the style of the transition itself. You don’t need to do a fade-flip-slide combo to wow the user, a subtle motion is enough to illustrate the result of the user interaction. Let's explore some of the transitions and transition settings that we can use in Adobe XD.</p>\n<ul>\n<li><em>Target</em> (what the screen transitions into):\n<ul>\n<li>None: Essentially removes the flow</li>\n<li>Previous Artboard: Returns to previous screen</li>\n<li>[Artboard Name]: Links to another screen</li>\n</ul>\n</li>\n<li><em>Transition</em> (the visual effect):\n<ul>\n<li>None: No transition</li>\n<li>Dissolve: Simple fade transition</li>\n<li>Slide Left: Slides over from the left</li>\n<li>Slide Right: Slides over from the right</li>\n<li>Slide Up: Slides over from the top</li>\n<li>Slide Down: Slides over from the bottom</li>\n<li>Push ←/→/↑/↓: Same as slide transition, except the screen sliding in <em>pushes</em> the current screen out</li>\n</ul>\n</li>\n<li><em>Easing</em> (the speed of each interval of the transition):\n<ul>\n<li>Ease-Out: Transition will start at full speed/finish slowly</li>\n<li>Ease-In: Transition will start slowly/finish at full speed</li>\n<li>Ease-In-Out: Start slow, full-speed at middle, finish slow</li>\n<li>None: The transition will not accelerate/decelerate (linear)</li>\n</ul>\n</li>\n<li><em>Duration</em>: Overall time it takes for the transition to complete</li>\n</ul>\n<p>For further reading on easings (notably, the different types of easings and their effect on user experience), check out my article on <a href=\"https://www.sitepoint.com/animations-using-easings-to-craft-smarter-interactions/\">micro-interactions and easings on SitePoint</a>.</p>\n<p>Because we linked the welcome screen to the set location screen, the <em>Target</em> setting has already been defined. <em>Slide Left</em> is a suitable option for the <em>Transition</em> setting because it creates motion (the destination screen slides in from the right, implying that it was the next screen in a series of screens — this is the default setting on iOS and some areas of Android).</p>\n<p><em>Ease-out</em> is a suitable easing for this user flow because it forces the animation to be faster at the beginning, creating a seemingly swift transition that doesn’t delay the user too much, then gracefully slows down so the user has a little extra time to understand what’s happened. In most cases, the default <em>Duration</em> setting of 0.4 seconds is more than optimal.</p>\n<p>Let's roll with these settings.</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508493601first-screen.png\" alt=\"First scren settings\" width=\"994\" height=\"612\" class=\"aligncenter size-full wp-image-160896\" /></p>\n<p>From the <em>Set Location</em> screen, create a user flow back to the <em>Welcome Screen</em>. Select <em>Previous Artboard</em> as the <em>Target</em>, which will automatically reverse the transition last used. For example, if you used <em>Slide Left</em> to enter the screen, <em>Slide Right</em> will be used as you return to the previous screen.</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508493634prev-screen.png\" alt=\"Previous artboard settings\" width=\"984\" height=\"609\" class=\"aligncenter size-full wp-image-160897\" /></p>\n<p>Repeat these steps, linking <em>Set Location</em> to <em>Search Results</em>.</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508493663second-screen.png\" alt=\"Linking a sceond screen\" width=\"761\" height=\"597\" class=\"aligncenter size-full wp-image-160898\" /></p>\n<p>And vice-versa.</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508493700vice-versa.png\" alt=\"Vice versa\" width=\"762\" height=\"527\" class=\"aligncenter size-full wp-image-160899\" /></p>\n<p>At any moment you can click on an artboard to see an overview of which screens link to it, and which screens it links to. Prototyping is wonderfully visual in Adobe XD!</p>\n<p>While apps like Marvel, Framer, Origami and InVision are certainly more <em>powerful</em> when it comes to prototyping (functionality like fixed elements, dynamic input fields and embeddable web content has existed in these apps for a while now), Adobe XD releases feature updates on a monthly basis. It’s catching up fast, and each version is reasonably stable.</p>\n<p>Besides that, Adobe XD offers something that no other design app does: a unified design + prototyping experience. XD is not a companion to a design app like Photoshop or Sketch, it <em>is</em> the design app, <em>and</em> the prototyping app. Being able to seamlessly switch between the <em>Design</em> and <em>Prototype</em> workspaces makes designing and prototyping with Adobe XD silky smooth.</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508493731overview.png\" alt=\"A user flow overview\" width=\"1366\" height=\"768\" class=\"aligncenter size-full wp-image-160900\" /></p>\n","protected":false},"excerpt":{"rendered":"<p><em>The following is a short extract from our book, <a href=\"https://www.sitepoint.com/premium/books/jump-start-adobe-xd\">Jump Start Adobe XD</a>, written by Daniel Schwarz, a highly practical tutorial on this fantastic prototyping tool. SitePoint Premium members get access with their membership, or you can buy a copy in stores worldwide.</em></p>\n<h2 id=\"prototyping-interactions\">Prototyping Interactions</h2>\n<p>Let's start by linking the welcome screen to the location filter screen, effectively demonstrating a user flow where the user searches for a type of cuisine, and is then asked to specify <em>where</em> they’d like to eat in the location filter screen. Click on the right arrow icon (inside the input field on the welcome screen), where a blue arrow-tab will appear alongside it.</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508493517start-flow.png\" alt=\"Creating a user flow\" width=\"978\" height=\"695\" class=\"aligncenter size-full wp-image-160894\" /></p>\n<p>Drag and drop this blue tab into the location filter screen. A user flow will have been created, and a small modal will appear where you can specify transition settings for this user flow – that is, how the screen will transition into the next one (the type of animation effect, the duration of that animation, etc).</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508493549flow-done.png\" alt=\"Flow and transition settings\" width=\"993\" height=\"608\" class=\"aligncenter size-full wp-image-160895\" /></p>\n<p>Later on (when we learn how to preview/test our prototypes), we’ll be able to literally click on this icon and be taken to the next screen, as if we were using a real app — this is how we (and our developers, and <em>maybe</em> even our clients) use the prototype workspace to test our concept before committing to it.</p>\n<p>Next, we’ll specify the transition settings for this user flow.</p>\n<h3 id=\"designing-transitions\">Designing Transitions</h3>\n<p>Animation comes with its own set of UX challenges. A slow transition can make the user feel like your app is taking too long, whereas a transition that’s too fast can leave the user wondering what even happened. And then there’s the style of the transition itself. You don’t need to do a fade-flip-slide combo to wow the user, a subtle motion is enough to illustrate the result of the user interaction. Let's explore some of the transitions and transition settings that we can use in Adobe XD.</p>\n<ul>\n<li><em>Target</em> (what the screen transitions into):\n<ul>\n<li>None: Essentially removes the flow</li>\n<li>Previous Artboard: Returns to previous screen</li>\n<li>[Artboard Name]: Links to another screen</li>\n</ul>\n</li>\n<li><em>Transition</em> (the visual effect):\n<ul>\n<li>None: No transition</li>\n<li>Dissolve: Simple fade transition</li>\n<li>Slide Left: Slides over from the left</li>\n<li>Slide Right: Slides over from the right</li>\n<li>Slide Up: Slides over from the top</li>\n<li>Slide Down: Slides over from the bottom</li>\n<li>Push ←/→/↑/↓: Same as slide transition, except the screen sliding in <em>pushes</em> the current screen out</li>\n</ul>\n</li>\n<li><em>Easing</em> (the speed of each interval of the transition):\n<ul>\n<li>Ease-Out: Transition will start at full speed/finish slowly</li>\n<li>Ease-In: Transition will start slowly/finish at full speed</li>\n<li>Ease-In-Out: Start slow, full-speed at middle, finish slow</li>\n<li>None: The transition will not accelerate/decelerate (linear)</li>\n</ul>\n</li>\n<li><em>Duration</em>: Overall time it takes for the transition to complete</li>\n</ul>\n<p>For further reading on easings (notably, the different types of easings and their effect on user experience), check out my article on <a href=\"https://www.sitepoint.com/animations-using-easings-to-craft-smarter-interactions/\">micro-interactions and easings on SitePoint</a>.</p>\n<p>Because we linked the welcome screen to the set location screen, the <em>Target</em> setting has already been defined. <em>Slide Left</em> is a suitable option for the <em>Transition</em> setting because it creates motion (the destination screen slides in from the right, implying that it was the next screen in a series of screens — this is the default setting on iOS and some areas of Android).</p>\n<p><em>Ease-out</em> is a suitable easing for this user flow because it forces the animation to be faster at the beginning, creating a seemingly swift transition that doesn’t delay the user too much, then gracefully slows down so the user has a little extra time to understand what’s happened. In most cases, the default <em>Duration</em> setting of 0.4 seconds is more than optimal.</p>\n<p>Let's roll with these settings.</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508493601first-screen.png\" alt=\"First scren settings\" width=\"994\" height=\"612\" class=\"aligncenter size-full wp-image-160896\" /></p>\n<p>From the <em>Set Location</em> screen, create a user flow back to the <em>Welcome Screen</em>. Select <em>Previous Artboard</em> as the <em>Target</em>, which will automatically reverse the transition last used. For example, if you used <em>Slide Left</em> to enter the screen, <em>Slide Right</em> will be used as you return to the previous screen.</p>\n","protected":false},"author":71978,"featured_media":161137,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[6131,8597,8760,5925,8005,412,8601],"tags":[9927,9797,9506,1097],"_links":{"self":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/posts/160893"}],"collection":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/posts"}],"about":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/types/post"}],"author":[{"embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/users/71978"}],"replies":[{"embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/comments?post=160893"}],"version-history":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/posts/160893/revisions"}],"wp_featuredmedia":[{"embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/media/161137"}],"wp_attachment":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/media?parent=160893"}],"wp_term":[{"taxonomy":"category","embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/categories?post=160893"},{"taxonomy":"post_tag","embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/tags?post=160893"}],"curies":[{"name":"wp","href":"https://api.w.org/{rel}","templated":true}]}}
{"index":{"_index":"blogs","_id":160867,"_type":"default"}}
{"id":160867,"date":"2017-10-27T09:00:41","date_gmt":"2017-10-27T16:00:41","guid":{"rendered":"https://www.sitepoint.com/?p=160867"},"modified":"2017-10-26T20:33:04","modified_gmt":"2017-10-27T03:33:04","slug":"what-can-we-prototype-what-cant-we-prototype","status":"publish","type":"post","link":"https://www.sitepoint.com/what-can-we-prototype-what-cant-we-prototype/","title":{"rendered":"UX: What Can We Prototype? What Can’t We Prototype?"},"content":{"rendered":"<p><em>The following is a short extract from our book, <a href=\"https://www.sitepoint.com/premium/books/designing-ux-prototyping\">Designing UX: Prototyping</a>, written by Dan Goodwin and Ben Coleman. It’s the ultimate guide to prototyping. SitePoint Premium members get access with their membership, or you can buy a copy in stores worldwide.</em></p>\n<h2 id=\"what-can-we-prototype-\">What can we prototype?</h2>\n<p>In simple terms, what we might consider creating a prototype for are the kinds of things that we might we otherwise use sketches and wireframes to explore and design.</p>\n<p>We'll now review some of the items for which prototypes are particularly helpful in the design of a website.</p>\n<h3 id=\"information-architecture-and-structural-elements\">Information Architecture and Structural Elements</h3>\n<p>Presenting a site’s structure as a sitemap diagram to the project team and stakeholders is often ineffective. It's even harder to user-test structural elements with such a diagram. At a more granular level, we have the same problem testing and presenting other aspects of information architecture including structure, behavior and labelling in navigation, or taxonomies (such as the categories users can employ to segment and query products in an online shop). </p>\n<p>It's possible to build an interactive prototype and populate it with real structural elements (for example, primary and secondary page navigation, product categories). Then we can test these structures: the page hierarchy, the behavior of the navigation, and the labels that we're proposing with real users given real tasks to perform. We can present our information architecture to stakeholders in an exciting, tangible way that they can visualize and explore.</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508430528what-ia-structural-elements.png\" alt=\"\" width=\"600\" height=\"393\" class=\"aligncenter size-full wp-image-160868\" /> </p>\n<p>This lends itself particularly well to the loading of real content for prototyping then being used for production. We can start at a low level of fidelity by loading the structure of a website into a content management system (CMS) database for a prototype. Then we can increase fidelity by adding placeholder content, then further still by adding in real content. This content can then potentially be used in a production implementation. We'll talk about this in detail in <a href=\"#chap7\">Chapter 7</a>.</p>\n<h3 id=\"layout-and-visual-hierarchy\">Layout and Visual Hierarchy</h3>\n<p>We can use a prototype to design, test, and communicate the overall layout and hierarchy of elements that make up a page. This is the kind of design where we’d traditionally use wireframes.</p>\n<p>Take the example of a site presenting a range of vacuum cleaners. We might have a list of all cleaners grouped or categorized in a certain way; for example, a page for each individual cleaner showing specifications, options, and user reviews. We have to decide what content to present in the listing and what to display on a single cleaner page, as well as how to lay them out.</p>\n<p>We can use insights from user research to help us, such as the tasks different types of users are trying to achieve, what information is needed to solve those tasks, and what’s considered important / less important. From there we can come up with a proposed layout for the listing and for the single page. Then we can implement that proposal in a prototype, ideally using some real content.</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508430563what-layout-visual-hierarchy-1.png\" alt=\"\" width=\"600\" height=\"537\" class=\"aligncenter size-full wp-image-160869\" /></p>\n<p>A prototype enables us to present the proposal to stakeholders and to test it with real users. Over the lifetime of our prototype, we can add, remove, and change content, as well as alter the layouts we're proposing. We can test small changes or radical alternatives to the layout. If our prototype’s implementation has a good separation of content and presentation, the process of changing the layout while maintaining the same base content is easy. That means we can test more layouts, more quickly and more easily.</p>\n<h3 id=\"interactive-elements\">Interactive Elements</h3>\n<p>All websites have at least some interactive elements (such as a link), but many have interactive elements that are more involved and complex. This requires significant amounts of user interface design.</p>\n<p>Consider the example of an ecommerce site selling clothes and accessories. Users tend to have varying requirements in narrowing their clothing searches, whether it’s by size, color, season, garment type, fabric, brand, and so on. This often leads designers of an ecommerce store to consider a <strong>faceted navigation pattern</strong>, where users can narrow their search across several sets of criteria––for example, medium size, yellow color, and cotton fabric––and see the results promptly.</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508430585what-interactive-elements.png\" alt=\"\" width=\"309\" height=\"450\" class=\"aligncenter size-full wp-image-160870\" /></p>\n<p>While it sounds straightforward enough, this is a remarkably complicated feature to design. The ability of a prototype to help us try out ideas for laying out categories, their method of interaction, and which categories to narrow results by will significantly improve our chances of doing it justice. We can use a decent set of representative content to quickly implement a range of ideas for presenting and interacting with that content. We can communicate our ideas with stakeholders and test them out with real users––iterating, changing, and experimenting as we go.</p>\n<p>Without a prototype, this kind of rapid iteration could only happen once the online store had been (at least) partially implemented. Prototyping allows us to do it earlier, quicker, and cheaper.</p>\n<h2 id=\"whatcant\">What <em>can't</em> we do with a prototype?</h2>\n<p>By now, I'm hoping you have plenty of ideas for a prototype and what can be achieved by creating one. That said, it's worth addressing what we’re unlikely to achieve with a prototype.</p>\n<h3 id=\"use-quantitative-research-to-make-decisions\">Use Quantitative Research to Make Decisions</h3>\n<p>If you're looking to try out some design ideas with a view to employing metrics to assess which is “better” (for example, more sign-ups, more conversions, highest task completion rate), a prototype is unlikely to help. For these kinds of tests, you need a large sample size––typically in the thousands or tens of thousands; however, utilizing quantitative research to make decisions such as these is beyond the scope of this book.</p>\n<p>It's worth pointing out, though, that prototypes generally <em>will</em> help you test your designs with a large number of users more successfully than alternatives such as sketches or wireframes. This is because of the ease of implementing, sharing, publishing and running tests with prototypes, and iterating these tests over and above the other methods.</p>\n<h3 id=\"testing-for-completion-conversion-funnel-progress\">Testing for Completion/Conversion Funnel Progress</h3>\n<p>It’s generally a bad idea to try to measure the success of a task completion/conversion funnel (for example, how far users of an ecommerce site progress along a sales funnel) with user tests, whether it be a prototype or with a production site<span class=\"fn\">Quantitative measurement of progress in goal funnels is covered in the SitePoint book <em>Researching UX: Analytics</em>: https://www.sitepoint.com/premium/books/researching-ux-analytics</span>.</p>\n<p>This is because in an observed user-testing scenario, users are motivated to complete the tasks they're presented with purely by the nature of being a participant in a user test. We might expect to hear comments along the lines of “I'd have given up by now,” which to a degree are useful. But since what users say they do and what they actually do can be two completely different things, such comments only help up to a point. When using a site in a natural context, user behavior in reality may be very different and tolerance for poor design much lower.</p>\n<h3 id=\"testing-accessibility\">Testing Accessibility</h3>\n<p>Most prototyping techniques fail to match the final production implementation and, as a result, can’t be used to test the accessibility of a design; for example, measuring the ability for users of assistive technologies to access content and features.</p>\n<p>Typically, HTML prototyping is done in a very rough-and-ready way, so coding standards and accessibility barely get a look-in. </p>\n<p>An accessible implementation is essential, and best audited and tested on a production site prior to launch and on an ongoing basis. That said, if you wanted to test the accessibility of certain features in a prototype (such as a complicated interactive element), there’s no reason why you couldn’t build those features to the relevant standards and test them.</p>\n<h3 id=\"testing-the-impact-of-visual-design\">Testing the Impact of Visual Design</h3>\n<p>Generally, prototypes are created at a level of fidelity that is too low to test the impact of visual design features such as font sizes, background colors, or borders on the visual hierarchy of a design.</p>\n<p>Some prototyping tools and techniques (such as InVision, discussed in <a href=\"#chap6\">Chapter 6</a>) do allow the creation of a prototype from high-fidelity design mockups. Hence, if you can come up with a sensible user-testing strategy, you could use these to test the impact of your visual design changes.</p>\n<h3 id=\"being-the-sole-source-of-documentation\">Being the Sole Source of Documentation</h3>\n<p>Agile (whether it’s little a or big A agile) prefers working software over comprehensive documentation, so it can be natural for some teams to rely solely on their evolving prototype to document what they're doing.</p>\n<p>Prototypes on their own don’t document the history of creating a design (although a good source-control workflow could help here). Therefore, it's important that you take care to document changes between versions when evolving your prototype. Similarly, a prototype alone won't always show enough to provide sufficient documentation for full design and development. Furthermore, it's too easy for stakeholders or project team members to miss an important feature because they failed to click on that part of the prototype. </p>\n<p>To mitigate these problems, consider how you can produce just enough supporting documentation and decision-making history so that the team can understand what’s been implemented and why.</p>\n","protected":false},"excerpt":{"rendered":"<p><em>The following is a short extract from our book, <a href=\"https://www.sitepoint.com/premium/books/designing-ux-prototyping\">Designing UX: Prototyping</a>, written by Dan Goodwin and Ben Coleman. It’s the ultimate guide to prototyping. SitePoint Premium members get access with their membership, or you can buy a copy in stores worldwide.</em></p>\n<h2 id=\"what-can-we-prototype-\">What can we prototype?</h2>\n<p>In simple terms, what we might consider creating a prototype for are the kinds of things that we might we otherwise use sketches and wireframes to explore and design.</p>\n<p>We'll now review some of the items for which prototypes are particularly helpful in the design of a website.</p>\n<h3 id=\"information-architecture-and-structural-elements\">Information Architecture and Structural Elements</h3>\n<p>Presenting a site’s structure as a sitemap diagram to the project team and stakeholders is often ineffective. It's even harder to user-test structural elements with such a diagram. At a more granular level, we have the same problem testing and presenting other aspects of information architecture including structure, behavior and labelling in navigation, or taxonomies (such as the categories users can employ to segment and query products in an online shop). </p>\n<p>It's possible to build an interactive prototype and populate it with real structural elements (for example, primary and secondary page navigation, product categories). Then we can test these structures: the page hierarchy, the behavior of the navigation, and the labels that we're proposing with real users given real tasks to perform. We can present our information architecture to stakeholders in an exciting, tangible way that they can visualize and explore.</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508430528what-ia-structural-elements.png\" alt=\"\" width=\"600\" height=\"393\" class=\"aligncenter size-full wp-image-160868\" /> </p>\n<p>This lends itself particularly well to the loading of real content for prototyping then being used for production. We can start at a low level of fidelity by loading the structure of a website into a content management system (CMS) database for a prototype. Then we can increase fidelity by adding placeholder content, then further still by adding in real content. This content can then potentially be used in a production implementation. We'll talk about this in detail in <a href=\"#chap7\">Chapter 7</a>.</p>\n<h3 id=\"layout-and-visual-hierarchy\">Layout and Visual Hierarchy</h3>\n<p>We can use a prototype to design, test, and communicate the overall layout and hierarchy of elements that make up a page. This is the kind of design where we’d traditionally use wireframes.</p>\n<p>Take the example of a site presenting a range of vacuum cleaners. We might have a list of all cleaners grouped or categorized in a certain way; for example, a page for each individual cleaner showing specifications, options, and user reviews. We have to decide what content to present in the listing and what to display on a single cleaner page, as well as how to lay them out.</p>\n<p>We can use insights from user research to help us, such as the tasks different types of users are trying to achieve, what information is needed to solve those tasks, and what’s considered important / less important. From there we can come up with a proposed layout for the listing and for the single page. Then we can implement that proposal in a prototype, ideally using some real content.</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508430563what-layout-visual-hierarchy-1.png\" alt=\"\" width=\"600\" height=\"537\" class=\"aligncenter size-full wp-image-160869\" /></p>\n<p>A prototype enables us to present the proposal to stakeholders and to test it with real users. Over the lifetime of our prototype, we can add, remove, and change content, as well as alter the layouts we're proposing. We can test small changes or radical alternatives to the layout. If our prototype’s implementation has a good separation of content and presentation, the process of changing the layout while maintaining the same base content is easy. That means we can test more layouts, more quickly and more easily.</p>\n<h3 id=\"interactive-elements\">Interactive Elements</h3>\n<p>All websites have at least some interactive elements (such as a link), but many have interactive elements that are more involved and complex. This requires significant amounts of user interface design.</p>\n<p>Consider the example of an ecommerce site selling clothes and accessories. Users tend to have varying requirements in narrowing their clothing searches, whether it’s by size, color, season, garment type, fabric, brand, and so on. This often leads designers of an ecommerce store to consider a <strong>faceted navigation pattern</strong>, where users can narrow their search across several sets of criteria––for example, medium size, yellow color, and cotton fabric––and see the results promptly.</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508430585what-interactive-elements.png\" alt=\"\" width=\"309\" height=\"450\" class=\"aligncenter size-full wp-image-160870\" /></p>\n<p>While it sounds straightforward enough, this is a remarkably complicated feature to design. The ability of a prototype to help us try out ideas for laying out categories, their method of interaction, and which categories to narrow results by will significantly improve our chances of doing it justice. We can use a decent set of representative content to quickly implement a range of ideas for presenting and interacting with that content. We can communicate our ideas with stakeholders and test them out with real users––iterating, changing, and experimenting as we go.</p>\n<p>Without a prototype, this kind of rapid iteration could only happen once the online store had been (at least) partially implemented. Prototyping allows us to do it earlier, quicker, and cheaper.</p>\n<h2 id=\"whatcant\">What <em>can't</em> we do with a prototype?</h2>\n<p>By now, I'm hoping you have plenty of ideas for a prototype and what can be achieved by creating one. That said, it's worth addressing what we’re unlikely to achieve with a prototype.</p>\n<h3 id=\"use-quantitative-research-to-make-decisions\">Use Quantitative Research to Make Decisions</h3>\n<p>If you're looking to try out some design ideas with a view to employing metrics to assess which is “better” (for example, more sign-ups, more conversions, highest task completion rate), a prototype is unlikely to help. For these kinds of tests, you need a large sample size––typically in the thousands or tens of thousands; however, utilizing quantitative research to make decisions such as these is beyond the scope of this book.</p>\n<p>It's worth pointing out, though, that prototypes generally <em>will</em> help you test your designs with a large number of users more successfully than alternatives such as sketches or wireframes. This is because of the ease of implementing, sharing, publishing and running tests with prototypes, and iterating these tests over and above the other methods.</p>\n<h3 id=\"testing-for-completion-conversion-funnel-progress\">Testing for Completion/Conversion Funnel Progress</h3>\n<p>It’s generally a bad idea to try to measure the success of a task completion/conversion funnel (for example, how far users of an ecommerce site progress along a sales funnel) with user tests, whether it be a prototype or with a production site<span class=\"fn\">Quantitative measurement of progress in goal funnels is covered in the SitePoint book <em>Researching UX: Analytics</em>: https://www.sitepoint.com/premium/books/researching-ux-analytics</span>.</p>\n<p>This is because in an observed user-testing scenario, users are motivated to complete the tasks they're presented with purely by the nature of being a participant in a user test. We might expect to hear comments along the lines of “I'd have given up by now,” which to a degree are useful. But since what users say they do and what they actually do can be two completely different things, such comments only help up to a point. When using a site in a natural context, user behavior in reality may be very different and tolerance for poor design much lower.</p>\n<h3 id=\"testing-accessibility\">Testing Accessibility</h3>\n<p>Most prototyping techniques fail to match the final production implementation and, as a result, can’t be used to test the accessibility of a design; for example, measuring the ability for users of assistive technologies to access content and features.</p>\n<p>Typically, HTML prototyping is done in a very rough-and-ready way, so coding standards and accessibility barely get a look-in. </p>\n","protected":false},"author":72471,"featured_media":161133,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[8572,6131,8597,8599,8005,8603,412,8601],"tags":[1954,9797,1097],"_links":{"self":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/posts/160867"}],"collection":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/posts"}],"about":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/types/post"}],"author":[{"embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/users/72471"}],"replies":[{"embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/comments?post=160867"}],"version-history":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/posts/160867/revisions"}],"wp_featuredmedia":[{"embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/media/161133"}],"wp_attachment":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/media?parent=160867"}],"wp_term":[{"taxonomy":"category","embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/categories?post=160867"},{"taxonomy":"post_tag","embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/tags?post=160867"}],"curies":[{"name":"wp","href":"https://api.w.org/{rel}","templated":true}]}}
{"index":{"_index":"blogs","_id":160855,"_type":"default"}}
{"id":160855,"date":"2017-10-25T09:00:09","date_gmt":"2017-10-25T16:00:09","guid":{"rendered":"https://www.sitepoint.com/?p=160855"},"modified":"2017-10-23T22:33:41","modified_gmt":"2017-10-24T05:33:41","slug":"model-view-controller-mvc-architecture-rails","status":"publish","type":"post","link":"https://www.sitepoint.com/model-view-controller-mvc-architecture-rails/","title":{"rendered":"Understanding the Model-View-Controller (MVC) Architecture in Rails"},"content":{"rendered":"<p><em>The following is a short extract from our book, <a href=\"https://www.sitepoint.com/premium/books/rails-novice-to-ninja\">Rails: Novice to Ninja, 3rd Edition</a>, written by Glenn Goodrich and Patrick Lenz. It’s the ultimate beginner’s guide to Rails. SitePoint Premium members get access with their membership, or you can buy a copy in stores worldwide.</em></p>\n<p>The model-view-controller (MVC) architecture that we first encountered in Chapter 1 is not unique to Rails. In fact, it predates both Rails and the Ruby language by many years. Rails, however, really takes the idea of separating an application's data, user interface, and control logic to a whole new level.</p>\n<p>Let's take a look at the concepts behind building an application using the MVC architecture. Once we have the theory in place, we'll see how it translates to our Rails code.</p>\n<h3 id=\"mvc-in-theory\">MVC in Theory</h3>\n<p><strong>MVC</strong> is a pattern for the architecture of a software application. It separates an application into the following components:</p>\n<ul>\n<li><strong>Models</strong> for handling data and business logic</li>\n<li><strong>Controllers</strong> for handling the user interface and application</li>\n<li><strong>Views</strong> for handling graphical user interface objects and presentation </li>\n</ul>\n<p>This separation results in user requests being processed as follows:</p>\n<ol>\n<li>The browser (on the client) sends a request for a page to the controller on the server.</li>\n<li>The controller retrieves the data it needs from the model in order to respond to the request.</li>\n<li>The controller gives the retrieved data to the view.</li>\n<li>The view is rendered and sent back to the client for the browser to display.</li>\n</ol>\n<p>This process is illustrated in Figure 4-2 below.</p>\n<p>\t\t\t<img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508423394rails-revealed_mvc-diagram.png\" alt=\"MVC in Rails\" width=\"572\" height=\"231\" class=\"aligncenter size-full wp-image-160856\" /></p>\n<p>Separating a software application into these three distinct components is a good idea for a number of reasons, including:</p>\n<ul>\n<li>\n<p><em>improved scalability</em> (the ability for an application to grow)–for example, if your application begins experiencing performance issues because database access is slow, you can upgrade the hardware running the database without other components being affected</p>\n</li>\n<li>\n<p><em>ease of maintenance</em>—as the components have a low dependency on each other, making changes to one (to fix bugs or change functionality) does not affect another</p>\n</li>\n<li>\n<p><em>reusability</em>—a model may be reused by multiple views</p>\n</li>\n</ul>\n<p>If you're struggling to get your head around the concept of MVC, don't worry. For now, what's important to remember is that your Rails application is separated into three distinct components. Jump back to the MVC diagram if you need to refer to it later on.</p>\n<h3 id=\"mvc-the-rails-way\">MVC the Rails Way</h3>\n<p>Rails promotes the concept that models, views, and controllers should be kept separate by storing the code for each element as separate files in separate directories. </p>\n<p>This is where the Rails directory structure that we created back in Chapter 2 comes into play. It's time to poke around a bit within that structure. If you take a look inside the <code>app</code> directory, depicted in Figure 4-3, you'll see some folders whose names might start to sound familiar.</p>\n<p>\t\t\t<img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508423439rails-revealed_app-subdir.png\" alt=\"\" width=\"222\" height=\"600\" class=\"aligncenter size-full wp-image-160857\" /></p>\n<p>As you can see, each component of the model-view-controller architecture has its place within the <code>app</code> subdirectory—the <code>models</code>, <code>views</code>, and <code>controllers</code> subdirectories respectively. (We'll talk about <code>assets</code> in Chapter 7, <code>helpers</code> in Chapter 6, and <code>mailers</code> later on in this chapter. <code>jobs</code> and <code>channels</code> are beyond the scope of this book.)</p>\n<p>This separation continues within the code that comprises the framework itself. The classes that form the core functionality of Rails reside within the following modules:</p>\n<dl>\n<dt><code>ActiveRecord</code></dt>\n<dd><code>ActiveRecord</code> is the module for handling business logic and database communication. It plays the role of model in our MVC architecture.<span class=\"fn\">While it might seem odd that <code>ActiveRecord</code> doesn't have the word “model” in its name, there is a reason for this: Active Record is also the name of a famous design pattern—one that this component implements in order to perform its role in the MVC world. Besides, if it had been called <code>ActionModel</code>, it would have sounded more like an overpaid Hollywood star than a software component …</span></dd>\n<dt><code>ActionController</code></dt>\n<dd><code>ActionController</code> is the component that handles browser requests and facilitates communication between the model and the view. Your controllers will inherit from this class. It forms part of the <code>ActionPack</code> library, a collection of Rails components that we'll explore in depth in Chapter 5.</dd>\n<dt><code>ActionView</code></dt>\n<dd>code>ActionView is the component that handles the presentation of pages returned to the client. Views inherit from this class, which is also part of the <code>ActionPack</code> library.</dd>\n<p>Let's take a closer look at each of these components in turn.</p>\n<h3 id=\"-activerecord-\">The <code>ActiveRecord</code> Module</h3>\n<p><code>ActiveRecord</code> is designed to handle all of an application's tasks that relate to the database, including:</p>\n<ul>\n<li>establishing a connection to the database server</li>\n<li>retrieving data from a table</li>\n<li>storing new data in the database</li>\n</ul>\n<p><code>ActiveRecord</code> has a few other neat tricks up its sleeve. Let's look at some of them now.</p>\n<h4 id=\"database-abstraction\">Database Abstraction</h4>\n<p><code>ActiveRecord</code> ships with database adapters to connect to SQLite, MySQL, and PostgreSQL. A large number of adapters are available for other popular database server packages, such as Oracle, MongoDB, and Microsoft SQL Server, via RubyGems.</p>\n<p>The <code>ActiveRecord</code> module is based on the concept of database abstraction. As a refresher from Chapter 1, database abstraction is a way of coding an application so that it isn't dependent upon any one database. Code that's specific to a particular database server is hidden safely in <code>ActiveRecord</code>, and invoked as needed. The result is that a Rails application is not bound to any specific database server software. Should you need to change the underlying database server at a later time, no changes to your application code are required.</p>\n<div class=\"box tip\">\n<h4>Note: The Jury's Out on ActiveRecord</h4>\n<div class=\"body\">\n<p>As I said, <code>ActiveRecord</code> is an implementation of the Active Record pattern. There are those that disagree with the approach taken by <code>ActiveRecord</code>, so you'll hear a lot about that, too. For now, I suggest you learn the way <code>ActiveRecord</code> works, then form your judgement of the implementation as you learn.</p>\n</p></div>\n</p></div>\n<p>Some examples of code that differ greatly between vendors, and which <code>ActiveRecord</code> abstracts, include:</p>\n<ul>\n<li>the process of logging into the database server</li>\n<li>date calculations</li>\n<li>handling of Boolean (<code>true</code>/<code>false</code>) data</li>\n<li>evolution of your database structure</li>\n</ul>\n<p>Before I can show you the magic of <code>ActiveRecord</code> in action, though, a little housekeeping is necessary.</p>\n<h4 id=\"database-tables\">Database Tables</h4>\n<p>Tables are the containers within a relational database that store our data in a structured manner, and they're made up of rows and columns. The rows map to individual objects, and the columns map to the attributes of those objects. The collection of all the tables in a database, and the relationships between those tables, is called the <strong>database schema</strong>. An example of a table is shown in Figure 4-4.</p>\n<p>\t\t\t<img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508423533rails-revealed_showing-db-table.png\" alt=\"\" width=\"996\" height=\"322\" class=\"aligncenter size-full wp-image-160859\" /></p>\n<p>In Rails, the naming of Ruby classes and database tables follows an intuitive pattern: if we have a table called <code>stories</code> that consists of five rows, this table will store the data for five <code>Story</code> objects. What's nice about the mapping between classes and tables is that there's no need to write code to achieve it; the mapping just happens, because <code>ActiveRecord</code> infers the name of the table from the name of the class.</p>\n<p>Note that the name of our class in Ruby is a singular noun (<code>Story</code>), but the name of the table is plural (<code>stories</code>). This relationship makes sense if you think about it: when we refer to a <code>Story</code> object in Ruby, we're dealing with a single story. But the SQL table holds a multitude of stories, so its name should be plural. While you can override these conventions—as is sometimes necessary when dealing with legacy databases—it's much easier to adhere to them.</p>\n<p>The close relationship between objects and tables extends even further. If our <code>stories</code> table were to have a <code>link</code> column, as our example in Figure 4-4 does, the data in this column would automatically be mapped to the <code>link</code> attribute in a <code>Story</code> object. And adding a new column to a table would cause an attribute of the same name to become available in all of that table's corresponding objects.</p>\n<p>So, let's create some tables to hold the stories we create.</p>\n<p>For the time being, we'll create a table using the old-fashioned approach of entering SQL into the SQLite console. You could type out the following SQL commands, although typing out SQL is no fun. Instead, I encourage you to download the following script from the code archive, and copy and paste it straight into your SQLite console that you invoked via the following command in the application directory:</p>\n<pre><code class=\"language-bash\">$ sqlite3 db/development.sqlite3\r\n\t\t\t</code></pre>\n<p>Once your SQLite console is up, paste in the following:</p>\n<pre><code class=\"language-sql\">CREATE TABLE stories (\r\n "id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,\r\n "name" varchar(255) DEFAULT NULL,\r\n "link" varchar(255) DEFAULT NULL,\r\n "created_at" datetime DEFAULT NULL,\r\n "updated_at" datetime DEFAULT NULL\r\n);\r\n\t\t\t</code></pre>\n<p>You don't have to worry about remembering these SQL commands to use in your own projects; instead, take heart in knowing that in Chapter 5 we'll look at migrations. Migrations are special Ruby classes that we can write to create database tables for our application without using any SQL at all.</p>\n<div class=\"box note\">\n<h4>Note: Seek some SQL Smarts</h4>\n<div class=\"body\">\n<p>Even though Rails abstracts away the SQL required to create tables and database objects, you'd be doing yourself a favor if you become familiar with SQL and its syntax. SitePoint has <a href=\"https://www.sitepoint.com/premium/books/simply-sql\">published a book</a> on learning SQL, so check that one out.</p>\n</p></div>\n</p></div>\n<h4 id=\"using-the-rails-console\">Using the Rails Console</h4>\n<p>Now that we have our <code>stories</code> table in place, let's exit the SQLite console (simply type <code>.quit</code>) and open up a Rails console. A Rails console is just like the interactive Ruby console (<code>irb</code>) that we used in Chapter 2, but with one key difference. In a Rails console, you have access to all the environment variables and classes that are available to your application while it's running. These are not available from within a standard <code>irb</code> console.</p>\n<p>To enter a Rails console, change to your <code>readit</code> folder, and enter the command <code>rails console</code> or <code>rails c</code>, as shown in the code that follows. The <code>>></code> prompt is ready to accept your commands:</p>\n<pre><code class=\"language-bash\">$ cd readit\r\n$ rails console\r\nLoading development environment (Rails 5.0.0)\r\n>>\r\n\t\t\t</code></pre>\n<h4 id=\"saving-an-object\">Saving an Object</h4>\n<p>To start using <code>ActiveRecord</code>, simply define a class that inherits from the <code>ActiveRecord::Base</code>. We touched on the <code>::</code> operator very briefly in Chapter 3, where we mentioned that it was a way to invoke class methods on an object. It can also be used to refer to classes that exist within a module, which is what we're doing here. Flip back to the section on object-oriented programming (OOP) inChapter 3 if you need a refresher on inheritance.</p>\n<p>Consider the following code snippet:</p>\n<pre><code class=\"langauge-ruby\">class Story < ActiveRecord::Base\r\nend\r\n\t\t\t</code></pre>\n<p>These two lines of code define a seemingly empty class called <code>Story</code>; however, this class is far from empty, as we'll soon see.</p>\n<p>From the Rails console, let's create this <code>Story</code> class and an instance of the class called <code>story</code> by entering these commands:</p>\n<pre><code class=\"langauge-html\">>> class Story < ActiveRecord::Base; end\r\n=> nil\r\n>> story = Story.new\r\n=> #<Story id: nil, name: nil, url: nil, created_at: nil,\r\n updated_at: nil>\r\n>> story.class\r\n=> Story(id: integer, name: string, link: string,\r\n created_at: datetime, updated_at: datetime)\r\n\t\t\t</code></pre>\n<p>As you can see, the syntax for creating a new <code>ActiveRecord</code> object is identical to the syntax we used to create other Ruby objects in Chapter 3. At this point, we've created a new <code>Story</code> object; however, this object exists in memory only—we're yet to store it in our database.</p>\n<p>We can confirm that our <code>Story</code> object hasn't been saved by checking the return value of the <code>new_record?</code> method:</p>\n<pre><code class=\"language-bash\">>> story.new_record?\r\n=> true\r\n\t\t\t</code></pre>\n<p>Since the object is yet to be saved, it will be lost when we exit the Rails console. To save it to the database, we invoke the object's save method:</p>\n<pre><code class=\"language-bash\">>> story.save\r\n=> true\r\n\t\t\t</code></pre>\n<p>Now that we've saved our object (a return value of <code>true</code> indicates that the save method was successful), our story is no longer a new record. It's even been assigned a unique ID:</p>\n<pre><code class=\"language-bash\">>> story.new_record?\r\n=> false\r\n>> story.id\r\n=> 1\r\n\t\t\t</code></pre>\n<h4 id=\"defining-relationships-between-objects\">Defining Relationships between Objects</h4>\n<p>As well as the basic functionality that we've just seen, <code>ActiveRecord</code> makes the process of defining relationships (or associations) between objects as easy as it can be. Of course, it's possible with some database servers to define such relationships entirely within the database schema. In order to put <code>ActiveRecord</code> through its paces, let's look at the way it defines these relationships within Rails instead.</p>\n<p>Object relationships can be defined in a variety of ways; the main difference between these relationships is the number of records that are specified in the relationship. The primary types of database association are:</p>\n<ul>\n<li>one-to-one associations</li>\n<li>one-to-many associations</li>\n<li>many-to-many associations</li>\n</ul>\n<p>Let's look at some examples of each of these associations. Feel free to type them into the Rails console if you like, for the sake of practice. Remember that your class definitions won't be saved, though—I'll show you how to define associations in a file later.</p>\n<p>Suppose our application has the following associations:</p>\n<ul>\n<li>\n<p>An <code>Author</code> can have one <code>Blog</code>:</p>\n<pre><code class=\"language-ruby\">class Author < ActiveRecord::Base\r\n has_one :weblog\r\nend\r\n\t\t\t</code></pre>\n</li>\n<li>\n<p>An <code>Author</code> can submit many <code>Stories</code>:</p>\n<pre><code class=\"language-ruby\">class Author < ActiveRecord::Base\r\n has_many :stories\r\nend\r\n\t\t\t</code></pre>\n</li>\n<li>\n<p>A <code>Story</code> belongs to an <code>Author</code>:</p>\n<pre><code class=\"language-ruby\">class Story < ActiveRecord::Base\r\n belongs_to :author\r\nend\r\n\t\t\t</code></pre>\n</li>\n<li>\n<p>A <code>Story</code> has, and belongs to, many different <code>Topic</code>s:</p>\n<pre><code class=\"language-ruby\">class Story < ActiveRecord::Base\r\n has_and_belongs_to_many :topics\r\nend\r\nclass Topic < ActiveRecord::Base\r\n has_and_belongs_to_many :stories\r\nend\r\n\t\t\t</code></pre>\n</li>\n</ul>\n<p>You're no doubt growing tired of typing class definitions into a console, only to have them disappear the moment you exit the console. For this reason, we won't go any further with the associations between our objects for now—instead we'll delve into the Rails <code>ActiveRecord</code> module in more detail in Chapter 5.</p>\n<h3 id=\"-actionpack-\">The <code>ActionPack</code> Library</h3>\n<p><code>ActionPack</code> is the name of the library that contains the view and controller parts of the MVC architecture. Unlike the <code>ActiveRecord</code> module, these modules are more intuitively named: <code>ActionController</code> and <code>ActionView</code>.</p>\n<p>Exploring application logic and presentation logic on the command line makes little sense; views and controllers <em>are</em> designed to interact with a web browser, after all! Instead, I'll provide a brief overview of the <code>ActionPack</code> components, and we'll cover the hands-on stuff in Chapter 5.</p>\n<h3 id=\"-actioncontroller-the-controller-\"><code>ActionController</code> (the Controller)</h3>\n<p>The <strong>controller</strong> handles the application logic of your program, acting as glue between the application's data, the presentation layer, and the web browser. In this role, a controller performs a number of tasks including:</p>\n<ul>\n<li>deciding how to handle a particular request (for example, whether to render a full page or just one part of it)</li>\n<li>retrieving data from the model to be passed to the view</li>\n<li>gathering information from a browser request and using it to create or update data in the model</li>\n</ul>\n<p>When we introduced the MVC diagram in Figure 4-2 earlier in this chapter, it might not have occurred to you that a Rails application can consist of a number of different controllers. Well, it can! Each controller is responsible for a specific part of the application.</p>\n<p>For our Readit application, we'll create:</p>\n<ul>\n<li>one controller for displaying story links, which we'll name <code>StoriesController</code></li>\n<li>another controller for handling user authentication, called <code>SessionsController</code></li>\n<li>a controller to display user pages, named <code>UsersController</code></li>\n<li>a controller to display comment pages, named <code>CommentsController</code></li>\n<li>a final controller to handle story voting, called <code>VotesController</code></li>\n</ul>\n<p>Every Rails application comes with an <code>ApplicationController</code> (which lives in <code>app/controllers/application_controller.rb</code>) that inherits from <code>ActionController::Base</code>. All our controllers will inherit from the <code>ApplicationController</code>,<span class=\"fn\">There will actually be an intermediate class between this class and the <code>ActionController::Base</code> class; however, this doesn't change the fact that <code>ActionController::Base</code> is the base class from which every controller inherits. We'll cover the creation of the <code>StoriesController</code> class in more detail in Chapter 5.</span> but they'll have different functionality that is implemented as instance methods. Here's a sample class definition for the <code>StoriesController</code> class:</p>\n<pre><code class=\"language-ruby\">class StoriesController < ApplicationController\r\n def index\r\n end\r\n\r\n def show\r\n end\r\nend\r\n\t\t\t</code></pre>\n<p>This simple class definition sets up our <code>StoriesController</code> with two empty methods: the <code>index</code> method, and the <code>show</code> method. We'll expand upon these methods in later chapters.</p>\n<p>Each controller resides in its own Ruby file (with a <code>.rb</code> extension), which lives within the <code>app/controllers</code> directory. The <code>StoriesController</code> class that we just defined, for example, would inhabit the file <code>app/controllers/stories_controller.rb</code>.</p>\n<div class=\"box attention\">\n<h4>Note: Naming Conventions for Classes and Files</h4>\n<div class=\"body\">\n<p>You'll have noticed by now that the names of classes and files follow different conventions:</p>\n<ul>\n<li>\n<p>Class names are written in CamelCase (each word beginning with a capital letter, with no spaces between words).<span class=\"fn\">There are actually two variations of CamelCase: one with an uppercase first letter (also known as PascalCase), and one with a lowercase first letter. The Ruby convention for class names requires an uppercase first letter.</span></p>\n</li>\n<li>\n<p>Filenames are written in lowercase, with underscores separating each word.</p>\n</li>\n</ul>\n<p>This is an important detail. If this convention is <em>not</em> followed, Rails will have a hard time locating your files. Luckily, you won't need to name your files manually very often, if ever, as you'll see when we look at generated code in Chapter 5.</p>\n</p></div>\n</p></div>\n<h3 id=\"-actionview-the-view-\"><code>ActionView</code> (the View)</h3>\n<p>As discussed earlier, one of the principles of MVC is that a view should contain presentation logic only. This principle holds that the code in a view should only perform actions that relate to displaying pages in the application; none of the code in a view should perform any complicated application logic, nor store or retrieve any data from the database. In Rails, everything that is sent to the web browser is handled by a view.</p>\n<p>Predictably, views are stored in the <code>app/views</code> folder of our application.</p>\n<p>A view need not actually contain any Ruby code at all—it may be the case that one of your views is a simple HTML file; however, it's more likely that your views will contain a combination of HTML and Ruby code, making the page more dynamic. The Ruby code is embedded in HTML using embedded Ruby (ERb) syntax.</p>\n<p>ERb allows server-side code to be scattered throughout an HTML file by wrapping that code in special tags. For example:</p>\n<pre><code class=\"langauge-html\"><strong><%= 'Hello World from Ruby!' %></strong>\r\n\t\t\t</code></pre>\n<p>There are two forms of the ERb tags pair: one that includes the equals sign, and one without it:</p>\n</dl>\n<dl>\n<dt><code><%= … %></code></dt>\n<dd>This tag pair is for regular output. The output of a Ruby expression between these tags will be displayed in the browser.</dd>\n<dt><code><% … %></code></dt>\n<dd>This tag pair is for execution. The output of a Ruby expression between these tags will not be displayed in the browser.</dd>\n</dl>\n<p>Here's an example of each ERb tag:</p>\n<pre><code class=\"labguage-html\"><%= 'This line is displayed in the browser' %>\r\n<% 'This line executes silently, without displaying any output' %>\r\n\t\t\t</code></pre>\n<p>You can place any Ruby code—be it simple or complex—between these tags.</p>\n<p>Creating an instance of a view is a little different to that of a model or controller. While <code>ActionView::Base</code> (the parent class for all views) is one of the base classes for views in Rails, the instantiation of a view is handled completely by the <code>ActionView</code> module. The only file a Rails developer needs to modify is the template, which is the file that contains the presentation code for the view. As you might have guessed, these templates are stored in the <code>app/views</code> folder.</p>\n<p>As with everything else Rails, a strict convention applies to the naming and storage of template files:</p>\n<ul>\n<li>A template has one-to-one mapping to the action (method) of a controller. The name of the template file matches the name of the action to which it maps.</li>\n<li>The folder that stores the template is named after the controller.</li>\n<li>\n<p>The extension of the template file is twofold and varies depending on the template's type and the actual language in which a template is written. By default, there are three types of extensions in Rails:</p>\n<dl>\n<dt><code>html.erb</code></dt>\n<dd>This is the extension for standard HTML templates that are sprinkled with ERb tags.</dd>\n<dt><code>xml.builder</code></dt>\n<dd>This extension is used for templates that output XML (for example, to generate RSS feeds for your application).</dd>\n<dt><code>json.builder</code></dt>\n<dd>This extension is used for templates that output JSON, which is a common data integration for APIs. We'll talk more about JSON in Chapter 9 on advanced topics.</dd>\n</dl>\n</li>\n</ul>\n<p>This convention may sound complicated, but it's actually quite intuitive. For example, consider the <code>StoriesController</code> class defined earlier. Invoking the <code>show</code> method for this controller would, by default, attempt to display the <code>ActionView</code> template that lived in the <code>app/views/stories</code> directory. Assuming the page was a standard HTML page (containing some ERb code), the name of this template would be <code>show.html.erb</code>.</p>\n<p>Rails also comes with special templates such as layouts and partials. <strong>Layouts</strong> are templates that control the global layout of an application, such as structures that remain unchanged between pages (the primary navigation menu, for instance). <strong>Partials</strong> are special subtemplates (the result of a template being split into separate files, such as a secondary navigation menu or a form) that can be used multiple times within the application. We'll cover both layouts and partials in Chapter 7.</p>\n<p>Communication between controllers and views occurs via instance variables that are populated from within the controller's action. Let's expand upon our sample <code>StoriesController</code> class to illustrate this point (no need to type any of this out just yet):</p>\n<pre><code class=\"langauge-ruby\">class StoriesController < ActionController::Base\r\n def index\r\n @variable = 'Value being passed to a view'\r\n end\r\nend\r\n\t\t\t</code></pre>\n<p>As you can see, the instance variable <code>@variable</code> is being assigned a string value within the controller's action. Through the magic of <code>ActionView</code>, this variable can now be referenced directly from the corresponding view, as shown in this code:</p>\n<pre><code class=\"langauge-ruby\"><p>The instance variable @variable contains: <%= @variable %></p>\r\n\t\t\t</code></pre>\n<p>This approach allows more complex computations to be performed outside the view—remember, it should only contain presentational logic—and allow the view to display just the end result of the computation.</p>\n<p>Rails also provides access to special containers, such as the <code>params</code> and <code>session</code> hashes. These contain such information as the current page request and the user's session. We'll make use of these hashes in the chapters that follow.</p>\n","protected":false},"excerpt":{"rendered":"<p><em>The following is a short extract from our book, <a href=\"https://www.sitepoint.com/premium/books/rails-novice-to-ninja\">Rails: Novice to Ninja, 3rd Edition</a>, written by Glenn Goodrich and Patrick Lenz. It’s the ultimate beginner’s guide to Rails. SitePoint Premium members get access with their membership, or you can buy a copy in stores worldwide.</em></p>\n<p>The model-view-controller (MVC) architecture that we first encountered in Chapter 1 is not unique to Rails. In fact, it predates both Rails and the Ruby language by many years. Rails, however, really takes the idea of separating an application's data, user interface, and control logic to a whole new level.</p>\n<p>Let's take a look at the concepts behind building an application using the MVC architecture. Once we have the theory in place, we'll see how it translates to our Rails code.</p>\n<h3 id=\"mvc-in-theory\">MVC in Theory</h3>\n<p><strong>MVC</strong> is a pattern for the architecture of a software application. It separates an application into the following components:</p>\n<ul>\n<li><strong>Models</strong> for handling data and business logic</li>\n<li><strong>Controllers</strong> for handling the user interface and application</li>\n<li><strong>Views</strong> for handling graphical user interface objects and presentation </li>\n</ul>\n<p>This separation results in user requests being processed as follows:</p>\n<ol>\n<li>The browser (on the client) sends a request for a page to the controller on the server.</li>\n<li>The controller retrieves the data it needs from the model in order to respond to the request.</li>\n<li>The controller gives the retrieved data to the view.</li>\n<li>The view is rendered and sent back to the client for the browser to display.</li>\n</ol>\n<p>This process is illustrated in Figure 4-2 below.</p>\n<p>\t\t\t<img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508423394rails-revealed_mvc-diagram.png\" alt=\"MVC in Rails\" width=\"572\" height=\"231\" class=\"aligncenter size-full wp-image-160856\" /></p>\n<p>Separating a software application into these three distinct components is a good idea for a number of reasons, including:</p>\n<ul>\n<li>\n<p><em>improved scalability</em> (the ability for an application to grow)–for example, if your application begins experiencing performance issues because database access is slow, you can upgrade the hardware running the database without other components being affected</p>\n</li>\n<li>\n<p><em>ease of maintenance</em>—as the components have a low dependency on each other, making changes to one (to fix bugs or change functionality) does not affect another</p>\n</li>\n<li>\n<p><em>reusability</em>—a model may be reused by multiple views</p>\n</li>\n</ul>\n<p>If you're struggling to get your head around the concept of MVC, don't worry. For now, what's important to remember is that your Rails application is separated into three distinct components. Jump back to the MVC diagram if you need to refer to it later on.</p>\n<h3 id=\"mvc-the-rails-way\">MVC the Rails Way</h3>\n<p>Rails promotes the concept that models, views, and controllers should be kept separate by storing the code for each element as separate files in separate directories. </p>\n<p>This is where the Rails directory structure that we created back in Chapter 2 comes into play. It's time to poke around a bit within that structure. If you take a look inside the <code>app</code> directory, depicted in Figure 4-3, you'll see some folders whose names might start to sound familiar.</p>\n<p>\t\t\t<img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508423439rails-revealed_app-subdir.png\" alt=\"\" width=\"222\" height=\"600\" class=\"aligncenter size-full wp-image-160857\" /></p>\n<p>As you can see, each component of the model-view-controller architecture has its place within the <code>app</code> subdirectory—the <code>models</code>, <code>views</code>, and <code>controllers</code> subdirectories respectively. (We'll talk about <code>assets</code> in Chapter 7, <code>helpers</code> in Chapter 6, and <code>mailers</code> later on in this chapter. <code>jobs</code> and <code>channels</code> are beyond the scope of this book.)</p>\n<p>This separation continues within the code that comprises the framework itself. The classes that form the core functionality of Rails reside within the following modules:</p>\n<dl>\n<dt><code>ActiveRecord</code></dt>\n<dd><code>ActiveRecord</code> is the module for handling business logic and database communication. It plays the role of model in our MVC architecture.<span class=\"fn\">While it might seem odd that <code>ActiveRecord</code> doesn't have the word “model” in its name, there is a reason for this: Active Record is also the name of a famous design pattern—one that this component implements in order to perform its role in the MVC world. Besides, if it had been called <code>ActionModel</code>, it would have sounded more like an overpaid Hollywood star than a software component …</span></dd>\n<dt><code>ActionController</code></dt>\n<dd><code>ActionController</code> is the component that handles browser requests and facilitates communication between the model and the view. Your controllers will inherit from this class. It forms part of the <code>ActionPack</code> library, a collection of Rails components that we'll explore in depth in Chapter 5.</dd>\n<dt><code>ActionView</code></dt>\n<dd>code>ActionView is the component that handles the presentation of pages returned to the client. Views inherit from this class, which is also part of the <code>ActionPack</code> library.</dd>\n<p>Let's take a closer look at each of these components in turn.</p>\n<h3 id=\"-activerecord-\">The <code>ActiveRecord</code> Module</h3>\n<p><code>ActiveRecord</code> is designed to handle all of an application's tasks that relate to the database, including:</p>\n<ul>\n<li>establishing a connection to the database server</li>\n<li>retrieving data from a table</li>\n<li>storing new data in the database</li>\n</ul>\n<p><code>ActiveRecord</code> has a few other neat tricks up its sleeve. Let's look at some of them now.</p>\n<h4 id=\"database-abstraction\">Database Abstraction</h4>\n<p><code>ActiveRecord</code> ships with database adapters to connect to SQLite, MySQL, and PostgreSQL. A large number of adapters are available for other popular database server packages, such as Oracle, MongoDB, and Microsoft SQL Server, via RubyGems.</p>\n<p>The <code>ActiveRecord</code> module is based on the concept of database abstraction. As a refresher from Chapter 1, database abstraction is a way of coding an application so that it isn't dependent upon any one database. Code that's specific to a particular database server is hidden safely in <code>ActiveRecord</code>, and invoked as needed. The result is that a Rails application is not bound to any specific database server software. Should you need to change the underlying database server at a later time, no changes to your application code are required.</p>\n<div class=\"box tip\">\n<h4>Note: The Jury's Out on ActiveRecord</h4>\n<div class=\"body\">\n<p>As I said, <code>ActiveRecord</code> is an implementation of the Active Record pattern. There are those that disagree with the approach taken by <code>ActiveRecord</code>, so you'll hear a lot about that, too. For now, I suggest you learn the way <code>ActiveRecord</code> works, then form your judgement of the implementation as you learn.</p>\n</p></div>\n</p></div>\n<p>Some examples of code that differ greatly between vendors, and which <code>ActiveRecord</code> abstracts, include:</p>\n<ul>\n<li>the process of logging into the database server</li>\n<li>date calculations</li>\n<li>handling of Boolean (<code>true</code>/<code>false</code>) data</li>\n<li>evolution of your database structure</li>\n</ul>\n<p>Before I can show you the magic of <code>ActiveRecord</code> in action, though, a little housekeeping is necessary.</p>\n<h4 id=\"database-tables\">Database Tables</h4>\n<p>Tables are the containers within a relational database that store our data in a structured manner, and they're made up of rows and columns. The rows map to individual objects, and the columns map to the attributes of those objects. The collection of all the tables in a database, and the relationships between those tables, is called the <strong>database schema</strong>. An example of a table is shown in Figure 4-4.</p>\n<p>\t\t\t<img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508423533rails-revealed_showing-db-table.png\" alt=\"\" width=\"996\" height=\"322\" class=\"aligncenter size-full wp-image-160859\" /></p>\n<p>In Rails, the naming of Ruby classes and database tables follows an intuitive pattern: if we have a table called <code>stories</code> that consists of five rows, this table will store the data for five <code>Story</code> objects. What's nice about the mapping between classes and tables is that there's no need to write code to achieve it; the mapping just happens, because <code>ActiveRecord</code> infers the name of the table from the name of the class.</p>\n<p>Note that the name of our class in Ruby is a singular noun (<code>Story</code>), but the name of the table is plural (<code>stories</code>). This relationship makes sense if you think about it: when we refer to a <code>Story</code> object in Ruby, we're dealing with a single story. But the SQL table holds a multitude of stories, so its name should be plural. While you can override these conventions—as is sometimes necessary when dealing with legacy databases—it's much easier to adhere to them.</p>\n<p>The close relationship between objects and tables extends even further. If our <code>stories</code> table were to have a <code>link</code> column, as our example in Figure 4-4 does, the data in this column would automatically be mapped to the <code>link</code> attribute in a <code>Story</code> object. And adding a new column to a table would cause an attribute of the same name to become available in all of that table's corresponding objects.</p>\n<p>So, let's create some tables to hold the stories we create.</p>\n<p>For the time being, we'll create a table using the old-fashioned approach of entering SQL into the SQLite console. You could type out the following SQL commands, although typing out SQL is no fun. Instead, I encourage you to download the following script from the code archive, and copy and paste it straight into your SQLite console that you invoked via the following command in the application directory:</p>\n<pre><code class=\"language-bash\">$ sqlite3 db/development.sqlite3\r\n\t\t\t</code></pre>\n<p>Once your SQLite console is up, paste in the following:</p>\n<pre><code class=\"language-sql\">CREATE TABLE stories (\r\n "id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,\r\n "name" varchar(255) DEFAULT NULL,\r\n "link" varchar(255) DEFAULT NULL,\r\n "created_at" datetime DEFAULT NULL,\r\n "updated_at" datetime DEFAULT NULL\r\n);\r\n\t\t\t</code></pre>\n<p>You don't have to worry about remembering these SQL commands to use in your own projects; instead, take heart in knowing that in Chapter 5 we'll look at migrations. Migrations are special Ruby classes that we can write to create database tables for our application without using any SQL at all.</p>\n<div class=\"box note\">\n<h4>Note: Seek some SQL Smarts</h4>\n<div class=\"body\">\n<p>Even though Rails abstracts away the SQL required to create tables and database objects, you'd be doing yourself a favor if you become familiar with SQL and its syntax. SitePoint has <a href=\"https://www.sitepoint.com/premium/books/simply-sql\">published a book</a> on learning SQL, so check that one out.</p>\n</p></div>\n</p></div>\n<h4 id=\"using-the-rails-console\">Using the Rails Console</h4>\n<p>Now that we have our <code>stories</code> table in place, let's exit the SQLite console (simply type <code>.quit</code>) and open up a Rails console. A Rails console is just like the interactive Ruby console (<code>irb</code>) that we used in Chapter 2, but with one key difference. In a Rails console, you have access to all the environment variables and classes that are available to your application while it's running. These are not available from within a standard <code>irb</code> console.</p>\n<p>To enter a Rails console, change to your <code>readit</code> folder, and enter the command <code>rails console</code> or <code>rails c</code>, as shown in the code that follows. The <code>>></code> prompt is ready to accept your commands:</p>\n<pre><code class=\"language-bash\">$ cd readit\r\n$ rails console\r\nLoading development environment (Rails 5.0.0)\r\n>>\r\n\t\t\t</code></pre>\n<h4 id=\"saving-an-object\">Saving an Object</h4>\n<p>To start using <code>ActiveRecord</code>, simply define a class that inherits from the <code>ActiveRecord::Base</code>. We touched on the <code>::</code> operator very briefly in Chapter 3, where we mentioned that it was a way to invoke class methods on an object. It can also be used to refer to classes that exist within a module, which is what we're doing here. Flip back to the section on object-oriented programming (OOP) inChapter 3 if you need a refresher on inheritance.</p>\n<p>Consider the following code snippet:</p>\n<pre><code class=\"langauge-ruby\">class Story < ActiveRecord::Base\r\nend\r\n\t\t\t</code></pre>\n<p>These two lines of code define a seemingly empty class called <code>Story</code>; however, this class is far from empty, as we'll soon see.</p>\n<p>From the Rails console, let's create this <code>Story</code> class and an instance of the class called <code>story</code> by entering these commands:</p>\n<pre><code class=\"langauge-html\">>> class Story < ActiveRecord::Base; end\r\n=> nil\r\n>> story = Story.new\r\n=> #<Story id: nil, name: nil, url: nil, created_at: nil,\r\n updated_at: nil>\r\n>> story.class\r\n=> Story(id: integer, name: string, link: string,\r\n created_at: datetime, updated_at: datetime)\r\n\t\t\t</code></pre>\n<p>As you can see, the syntax for creating a new <code>ActiveRecord</code> object is identical to the syntax we used to create other Ruby objects in Chapter 3. At this point, we've created a new <code>Story</code> object; however, this object exists in memory only—we're yet to store it in our database.</p>\n<p>We can confirm that our <code>Story</code> object hasn't been saved by checking the return value of the <code>new_record?</code> method:</p>\n<pre><code class=\"language-bash\">>> story.new_record?\r\n=> true\r\n\t\t\t</code></pre>\n<p>Since the object is yet to be saved, it will be lost when we exit the Rails console. To save it to the database, we invoke the object's save method:</p>\n<pre><code class=\"language-bash\">>> story.save\r\n=> true\r\n\t\t\t</code></pre>\n<p>Now that we've saved our object (a return value of <code>true</code> indicates that the save method was successful), our story is no longer a new record. It's even been assigned a unique ID:</p>\n<pre><code class=\"language-bash\">>> story.new_record?\r\n=> false\r\n>> story.id\r\n=> 1\r\n\t\t\t</code></pre>\n<h4 id=\"defining-relationships-between-objects\">Defining Relationships between Objects</h4>\n<p>As well as the basic functionality that we've just seen, <code>ActiveRecord</code> makes the process of defining relationships (or associations) between objects as easy as it can be. Of course, it's possible with some database servers to define such relationships entirely within the database schema. In order to put <code>ActiveRecord</code> through its paces, let's look at the way it defines these relationships within Rails instead.</p>\n<p>Object relationships can be defined in a variety of ways; the main difference between these relationships is the number of records that are specified in the relationship. The primary types of database association are:</p>\n</dl>\n","protected":false},"author":71101,"featured_media":161036,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[8,71],"tags":[162,38,9767],"_links":{"self":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/posts/160855"}],"collection":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/posts"}],"about":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/types/post"}],"author":[{"embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/users/71101"}],"replies":[{"embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/comments?post=160855"}],"version-history":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/posts/160855/revisions"}],"wp_featuredmedia":[{"embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/media/161036"}],"wp_attachment":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/media?parent=160855"}],"wp_term":[{"taxonomy":"category","embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/categories?post=160855"},{"taxonomy":"post_tag","embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/tags?post=160855"}],"curies":[{"name":"wp","href":"https://api.w.org/{rel}","templated":true}]}}
{"index":{"_index":"blogs","_id":161103,"_type":"default"}}
{"id":161103,"date":"2017-10-25T08:30:53","date_gmt":"2017-10-25T15:30:53","guid":{"rendered":"https://www.sitepoint.com/?p=161103"},"modified":"2017-10-24T21:07:47","modified_gmt":"2017-10-25T04:07:47","slug":"5-top-web-apps-web-design-workflow","status":"publish","type":"post","link":"https://www.sitepoint.com/5-top-web-apps-web-design-workflow/","title":{"rendered":"5 Top Web Apps for Your Web Design Workflow"},"content":{"rendered":"<p class=\"wp-special\"><em>This article was sponsored by <a href=\"https://bawmedia.com/\" rel=\"nofollow\">BAWMedia</a>. Thank you for supporting the partners who make SitePoint possible.</em></p>\n<p>Your talent and creative instincts can take you a long way. Nevertheless, the web design process requires dedication and perseverance on top of plenty of hard work.</p>\n<p>Fortunately, there’s a host of apps on the market that are designed to make web design easier. The ultimate goal behind these apps: to make the designer more productive.</p>\n<p>New web apps make an appearance every day, or at least it seems like they do. There’s always something to try out that might make your workday just that much easier.</p>\n<p>Most web apps are easy to use and they work on almost all platforms. They also can be accessed from any device, and there’s nothing to install.</p>\n<h2 id=\"apptivohttpwwwapptivocomcrmsystemutm_sourcesitepointcomamputm_mediumcontentamputm_campaignbawwebapps\"><a href=\"http://www.apptivo.com/crm-system/?utm_source=sitepoint.com&utm_medium=content&utm_campaign=bawwebapps\">Apptivo</a></h2>\n<p><iframe width=\"500\" height=\"281\" src=\"https://www.youtube.com/embed/JqXqAXA_iUo?feature=oembed\" frameborder=\"0\" gesture=\"media\" allowfullscreen></iframe></p>\n<p><a href=\"https://www.youtube.com/watch?v=JqXqAXA_iUo\">View video on YouTube</a></p>\n<p>Managing customer relations can be tricky, complex, tedious, or all the above. Apptivo’s CRM web app provides the powerful capabilities you need to get and keep everything under control.</p>\n<p>You can access <a href=\"http://www.apptivo.com/crm-system/?utm_source=sitepoint.com&utm_medium=content&utm_campaign=bawwebapps\">Apptivo</a> from your browser, or from your iOS or Android device, and integrate it with your Office 365 suite.</p>\n<h2 id=\"webflowhttpwwwwebflowcomutm_sourcesitepointcomamputm_mediumcontentamputm_campaignbawwebapps\"><a href=\"http://www.webflow.com/?utm_source=sitepoint.com&utm_medium=content&utm_campaign=bawwebapps\">Webflow</a></h2>\n<p><iframe width=\"500\" height=\"281\" src=\"https://www.youtube.com/embed/ikCXeZT59RE?feature=oembed\" frameborder=\"0\" gesture=\"media\" allowfullscreen></iframe></p>\n<p><a href=\"https://www.youtube.com/watch?v=ikCXeZT59RE\">View video on YouTube</a></p>\n<p>If you need a web app that enables you to design and develop responsive websites without needing to write code, <a href=\"http://www.webflow.com/?utm_source=sitepoint.com&utm_medium=content&utm_campaign=bawwebapps\">Webflow</a> may be the solution. With Webflow, you can design exactly what you envision without being constrained by a template, create your own bespoke CMS for yourself or any content, and design with real content.</p>\n<h2 id=\"paymohttpswwwpaymoappcomprojectmanagementutm_sourcearticleamputm_mediumreviewamputm_campaignbaw_oct17\"><a href=\"https://www.paymoapp.com/project-management/?utm_source=article&utm_medium=review&utm_campaign=Baw_Oct17\">Paymo</a></h2>\n<p><iframe width=\"500\" height=\"281\" src=\"https://www.youtube.com/embed/HE11LOqpUqE?feature=oembed\" frameborder=\"0\" gesture=\"media\" allowfullscreen></iframe></p>\n<p><a href=\"https://www.youtube.com/watch?v=HE11LOqpUqE\">View video on YouTube</a></p>\n<p>Project management software can often be a hassle to install. <a href=\"https://www.paymoapp.com/project-management/?utm_source=article&utm_medium=review&utm_campaign=Baw_Oct17\">Paymo</a> is a project management web app, which means there is nothing to install. Paymo helps you manage your projects from start to finish, including task management, time tracking and resource scheduling.</p>\n<h2 id=\"nutcachehttpwwwnutcachecomutm_sourcebaw_mediaamputm_mediumnewsletteramputm_campaigntop_web_apps\"><a href=\"http://www.nutcache.com/?utm_source=baw_media&utm_medium=newsletter&utm_campaign=top_web_apps\">Nutcache</a></h2>\n<p><iframe width=\"500\" height=\"281\" src=\"https://www.youtube.com/embed/hxaBe_zLADk?feature=oembed\" frameborder=\"0\" gesture=\"media\" allowfullscreen></iframe></p>\n<p><a href=\"https://www.youtube.com/watch?v=hxaBe_zLADk\">View video on YouTube</a></p>\n<p><a href=\"http://www.nutcache.com/?utm_source=baw_media&utm_medium=newsletter&utm_campaign=top_web_apps\">Nutcache</a> is a business-oriented web app, designed to help teams manage Agile and Scrum projects smarter and more efficiently. Moreover, it provides the project management tools to organize the entire project lifecycle, from planning and initial estimating, to delivery and final billing.</p>\n<h2 id=\"pcloudhttpswwwpcloudcomutm_sourcesitepointcomamputm_mediumcontentamputm_campaignbawwebapps\"><a href=\"https://www.pcloud.com/?utm_source=sitepoint.com&utm_medium=content&utm_campaign=bawwebapps\">pCloud</a></h2>\n<p><iframe width=\"500\" height=\"281\" src=\"https://www.youtube.com/embed/Pwcno98gpVg?feature=oembed\" frameborder=\"0\" gesture=\"media\" allowfullscreen></iframe></p>\n<p><a href=\"https://www.youtube.com/watch?v=Pwcno98gpVg\">View video on YouTube</a></p>\n<p>If you’re losing sleep worrying about the data stored on your hard drive, consider storing it in the cloud with <a href=\"https://www.pcloud.com/?utm_source=sitepoint.com&utm_medium=content&utm_campaign=bawwebapps\">pCloud</a>. Your data is not only safe and secure, but you can access it 24/7 on your computer, tablet, or mobile device. Best of all you have the option to pay only once.</p>\n<h2 id=\"keepingupwithwebdesigndevelopmenttoolsandtrends\">Keeping Up with Web Design & Development Tools and Trends</h2>\n<p>It’s not always easy to keep up with the latest trends in the wonderful world of web design. You’d rather spend your time designing than trying to keep up with the latest technologies.</p>\n<p>Still, you should take the time to seek ways to become more skilled and efficient. A very good way to do so is to automate tasks that tend to be tedious and time-consuming (not to mention prone to error).</p>\n<p>Time spent looking for new tools and techniques can be viewed as a great investment. You can earn a nice return on that investment in terms of time saved, and enjoy what you do best all that much more.</p>\n<p>Devote some of that time to reading the reviews to see what others are saying.</p>\n<h2 id=\"conclusion\">Conclusion</h2>\n<p>Over time, web designers tend to accumulate a basic set of tools they rely on to get the job done. These tools run the gamut from design and development aids to data storage. They also include project business management.</p>\n<p>There will always be some manual processes that can be automated. Or, perhaps, there are automated processes that can be improved upon — so it’s best to always keep looking.</p>\n","protected":false},"excerpt":{"rendered":"<p class=\"wp-special\"><em>This article was sponsored by <a href=\"https://bawmedia.com/\" rel=\"nofollow\">BAWMedia</a>. Thank you for supporting the partners who make SitePoint possible.</em></p>\n<p>Your talent and creative instincts can take you a long way. Nevertheless, the web design process requires dedication and perseverance on top of plenty of hard work.</p>\n<p>Fortunately, there’s a host of apps on the market that are designed to make web design easier. The ultimate goal behind these apps: to make the designer more productive.</p>\n<p>New web apps make an appearance every day, or at least it seems like they do. There’s always something to try out that might make your workday just that much easier.</p>\n<p>Most web apps are easy to use and they work on almost all platforms. They also can be accessed from any device, and there’s nothing to install.</p>\n<h2 id=\"apptivohttpwwwapptivocomcrmsystemutm_sourcesitepointcomamputm_mediumcontentamputm_campaignbawwebapps\"><a href=\"http://www.apptivo.com/crm-system/?utm_source=sitepoint.com&utm_medium=content&utm_campaign=bawwebapps\">Apptivo</a></h2>\n<p>https://www.youtube.com/watch?v=JqXqAXA_iUo</p>\n<p><a href=\"https://www.youtube.com/watch?v=JqXqAXA_iUo\">View video on YouTube</a></p>\n<p>Managing customer relations can be tricky, complex, tedious, or all the above. Apptivo’s CRM web app provides the powerful capabilities you need to get and keep everything under control.</p>\n<p>You can access <a href=\"http://www.apptivo.com/crm-system/?utm_source=sitepoint.com&utm_medium=content&utm_campaign=bawwebapps\">Apptivo</a> from your browser, or from your iOS or Android device, and integrate it with your Office 365 suite.</p>\n<h2 id=\"webflowhttpwwwwebflowcomutm_sourcesitepointcomamputm_mediumcontentamputm_campaignbawwebapps\"><a href=\"http://www.webflow.com/?utm_source=sitepoint.com&utm_medium=content&utm_campaign=bawwebapps\">Webflow</a></h2>\n<p>https://www.youtube.com/watch?v=ikCXeZT59RE</p>\n<p><a href=\"https://www.youtube.com/watch?v=ikCXeZT59RE\">View video on YouTube</a></p>\n<p>If you need a web app that enables you to design and develop responsive websites without needing to write code, <a href=\"http://www.webflow.com/?utm_source=sitepoint.com&utm_medium=content&utm_campaign=bawwebapps\">Webflow</a> may be the solution. With Webflow, you can design exactly what you envision without being constrained by a template, create your own bespoke CMS for yourself or any content, and design with real content.</p>\n<h2 id=\"paymohttpswwwpaymoappcomprojectmanagementutm_sourcearticleamputm_mediumreviewamputm_campaignbaw_oct17\"><a href=\"https://www.paymoapp.com/project-management/?utm_source=article&utm_medium=review&utm_campaign=Baw_Oct17\">Paymo</a></h2>\n<p>https://www.youtube.com/watch?v=HE11LOqpUqE</p>\n<p><a href=\"https://www.youtube.com/watch?v=HE11LOqpUqE\">View video on YouTube</a></p>\n<p>Project management software can often be a hassle to install. <a href=\"https://www.paymoapp.com/project-management/?utm_source=article&utm_medium=review&utm_campaign=Baw_Oct17\">Paymo</a> is a project management web app, which means there is nothing to install. Paymo helps you manage your projects from start to finish, including task management, time tracking and resource scheduling.</p>\n<h2 id=\"nutcachehttpwwwnutcachecomutm_sourcebaw_mediaamputm_mediumnewsletteramputm_campaigntop_web_apps\"><a href=\"http://www.nutcache.com/?utm_source=baw_media&utm_medium=newsletter&utm_campaign=top_web_apps\">Nutcache</a></h2>\n","protected":false},"author":72596,"featured_media":161106,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[6131],"tags":[808,6298,3110],"_links":{"self":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/posts/161103"}],"collection":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/posts"}],"about":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/types/post"}],"author":[{"embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/users/72596"}],"replies":[{"embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/comments?post=161103"}],"version-history":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/posts/161103/revisions"}],"wp_featuredmedia":[{"embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/media/161106"}],"wp_attachment":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/media?parent=161103"}],"wp_term":[{"taxonomy":"category","embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/categories?post=161103"},{"taxonomy":"post_tag","embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/tags?post=161103"}],"curies":[{"name":"wp","href":"https://api.w.org/{rel}","templated":true}]}}
{"index":{"_index":"blogs","_id":160660,"_type":"default"}}
{"id":160660,"date":"2017-10-24T22:20:43","date_gmt":"2017-10-25T05:20:43","guid":{"rendered":"https://www.sitepoint.com/?p=160660"},"modified":"2017-10-26T15:10:15","modified_gmt":"2017-10-26T22:10:15","slug":"how-to-get-started-with-material-design-for-bootstrap","status":"publish","type":"post","link":"https://www.sitepoint.com/how-to-get-started-with-material-design-for-bootstrap/","title":{"rendered":"How to Get Started with Material Design for Bootstrap"},"content":{"rendered":"<p class=\"wp-special\"><em>This article was sponsored by <a href=\"https://mdbootstrap.com/?utm_source=sitePoint&utm_campaign=sitePoint-MDBFree-sponsoredPost&utm_medium=link&utm_content=documentationLink\" rel=\"nofollow\">MDBootstrap</a>. Thank you for supporting the partners who make SitePoint possible.</em></p>\n<p><img class=\"aligncenter size-large wp-image-161047\" src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508824168img1-1024x540.jpg\" alt=\"Material Design for Bootstrap\" width=\"1024\" height=\"540\" /></p>\n<p>As a SitePoint reader, you’re undoubtedly interested in creating bleeding-edge, sophisticated web sites and applications. You may not write everything from scratch, but you want a deep understanding of the code. You need nothing more than a text editor to build your next award-winning masterpiece.</p>\n<p>Unfortunately, working life isn’t always so simple. You could be taking your first steps toward becoming a web development ninja. Your boss may want something completed within hours rather than days. Your client could be at the lower end of the budgetary spectrum. You need something practical developed quickly and painlessly within a few hours.</p>\n<p>Many would consider a CMS such as WordPress. It’s a good option but it can be overkill and take too much time. Novice coders may be daunted by hosting requirements, PHP set-ups, MySQL database creation and the WordPress ecosystem. Even if your initial installation goes smoothly, you need to locate, install, configure and use appropriate themes and plugins.</p>\n<h2 id=\"enterthemdbootstrapuikit\">Enter the MDBootstrap UI Kit</h2>\n<p>Fortunately, there is an easier alternative. <a href=\"https://mdbootstrap.com/?utm_source=sitePoint&utm_campaign=sitePoint-MDBFree-sponsoredPost&utm_medium=link&utm_content=documentationLink\" rel=\"nofollow\">Material Design for Bootstrap (mdbootstrap.com)</a> provides a set of slick, responsive page templates, layouts, components and widgets to rapidly build web pages. There’s no complication or fuss: <em>you just copy and paste code into one or more HTML files</em>. It’ll help if you have a basic understanding of client-side web development but even those with a rudimentary knowledge of HTML can build an attractive page within minutes.</p>\n<p>The <a href=\"https://mdbootstrap.com/getting-started/?utm_source=sitePoint&utm_campaign=sitePoint-MDBFree-sponsoredPost&utm_medium=link&utm_content=documentationLink\" rel=\"nofollow\">free edition</a> has more than 400 components to choose from. The <a href=\"https://mdbootstrap.com/product/material-design-for-bootstrap-pro/?utm_source=sitePoint&utm_campaign=sitePoint-MDBFree-sponsoredPost&utm_medium=link&utm_content=mdbProLink\" rel=\"nofollow\">commercial PRO edition</a> contains more than 2,000 components with additional templates, tutorials, tools, and support. Both editions come in <a href=\"https://mdbootstrap.com/?utm_source=sitePoint&utm_campaign=sitePoint-MDBFree-sponsoredPost&utm_medium=link&utm_content=documentationLink\" rel=\"nofollow\">jQuery</a>, <a href=\"https://mdbootstrap.com/angular/?utm_source=sitePoint&utm_campaign=sitePoint-MDBFree-sponsoredPost&utm_medium=link&utm_content=documentationLink\" rel=\"nofollow\">Angular 4</a>, or <a href=\"https://mdbootstrap.com/react/?utm_source=sitePoint&utm_campaign=sitePoint-MDBFree-sponsoredPost&utm_medium=link&utm_content=documentationLink\" rel=\"nofollow\">React</a> flavors so you can select the most appropriate framework <em>(if in doubt, stick with jQuery, which has a shallower learning curve and legacy browser support)</em>. If necessary, your resulting page templates can be <a href=\"https://mdbootstrap.com/wordpress-tutorial/?utm_source=sitePoint&utm_campaign=sitePoint-MDBFree-sponsoredPost&utm_medium=link&utm_content=documentationLink\" rel=\"nofollow\">imported into WordPress</a> so your client can add and update content.</p>\n<p>Here’s the final product we’ll be building in this tutorial:</p>\n<p><img class=\"aligncenter size-full wp-image-161045\" src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508824097MDB-Preview.jpg\" alt=\"Material Design for Bootstrap Project Preview\" width=\"1000\" height=\"1978\" /></p>\n<p>You can check out a <a href=\"http://s3.sitepoint.com/examples/mdb-livepreview/index.html\" rel=\"nofollow\">live preview of our finished product here</a>.</p>\n<p>To create this, we’ll be incorporating a range of elements from Material Design for Bootstrap:</p>\n<ul>\n<li>Navigation</li>\n<li>A carousel</li>\n<li>A feature overview section</li>\n<li>Blockquote styling from the typography library</li>\n<li>A recent posts section</li>\n<li>… and a footer</li>\n</ul>\n<p>Install MDBootstrap by downloading and extracting the ZIP file to an appropriate location on your PC. You can use any folder since most pages will open in a browser directly from your file system. That said, I’d recommend you place them in a web server folder — especially if you intend to use JavaScript-powered components. If you don’t have a server installed, a quick option is <a href=\"https://www.npmjs.com/package/http-server\" rel=\"nofollow\">http-server for Node.js</a> (which exposes the current folder as a web root) or an all-in-one package such as <a href=\"https://www.apachefriends.org/\" rel=\"nofollow\">XAMPP</a>. Alternatively, you may be able to upload the files to your web host and edit there using a compatible editor such as <a href=\"https://codeanywhere.com/\" rel=\"nofollow\">codeanywhere</a>.</p>\n<h2 id=\"yourfirstmdbootstrappage\">Your First MDBootstrap Page</h2>\n<p>Open <code>index.html</code> in your web browser and you’ll see a home page with a welcome message:</p>\n<p><img class=\"aligncenter size-large wp-image-160665\" src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508135777mdb-01initial.png\" alt=\"initial welcome message\" width=\"813\" height=\"234\" /></p>\n<p>Now open <code>index.html</code> in your text editor or IDE of choice (perhaps the fabulous and free <a href=\"https://code.visualstudio.com/\" rel=\"nofollow\">VS Code</a> or <a href=\"https://atom.io/\" rel=\"nofollow\">Atom</a>). Delete the lines of HTML between:</p>\n<pre><code class=\"markup language-markup\"><!-- Start your project here-->\r\n</code></pre>\n<p>and</p>\n<pre><code class=\"markup language-markup\"><!-- /Start your project here-->\r\n</code></pre>\n<p>then replace them with:</p>\n<pre><code class=\"markup language-markup\"><div class=\"container-fluid\">\r\n\r\n <h1>Welcome</h1>\r\n <p>This is my first MDBootstrap page.</p>\r\n\r\n</div>\r\n</code></pre>\n<p>The code defines a container which provides a margin and responds to the browser width. It contains a title and paragraph:</p>\n<p><img class=\"aligncenter size-large wp-image-160666\" src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508135779mdb-02first.png\" alt=\"your first page\" width=\"273\" height=\"76\" /></p>\n<h2 id=\"copyinghtmlandcss\">Copying HTML and CSS</h2>\n<p>You’re now ready to insert your own components. Head over to <a href=\"https://mdbootstrap.com/?utm_source=sitePoint&utm_campaign=sitePoint-MDBFree-sponsoredPost&utm_medium=link&utm_content=documentationLink\" rel=\"nofollow\">mdbootstrap.com</a> and click the menu icon at the top-left of the page. A long list of categorized components can be selected.</p>\n<p>Most components require you to insert HTML into your page. Some also require additional CSS styles which should be copied and pasted into the (initially empty) <code>css/style.css</code> file. A link to this stylesheet is already provided in the HTML <code><head></code>:</p>\n<pre><code class=\"markup language-markup\"><link href=\"css/style.css\" rel=\"stylesheet\">\r\n</code></pre>\n<h2 id=\"creatinganadvancedlayout\">Creating an Advanced Layout</h2>\n<p>Now we’ll start building the more advanced layout that we previewed at the start of the tutorial.</p>\n<p>Make sure you revert back to an empty page by removing the code between:</p>\n<pre><code class=\"markup language-markup\"><!-- Start your project here-->\r\n</code></pre>\n<p>and</p>\n<pre><code class=\"markup language-markup\"><!-- /Start your project here-->\r\n</code></pre>\n<h2 id=\"addnavigation\">Add Navigation</h2>\n<p>The <a href=\"https://mdbootstrap.com/layout/bootstrap-navigation/?utm_source=sitePoint&utm_campaign=sitePoint-MDBFree-sponsoredPost&utm_medium=link&utm_content=documentationLink\" rel=\"nofollow\">MDBootstrap Layout / Navigation</a> provides a variety of options which collapse to hamburger menus when space is limited. The <a href=\"https://mdbootstrap.com/layout/bootstrap-navigation/#r-f-n?utm_source=sitePoint&utm_campaign=sitePoint-MDBFree-sponsoredPost&utm_medium=link&utm_content=documentationLink\" rel=\"nofollow\">Regular Fixed Navbar</a> HTML can be copied into the page immediately after <code><!-- Start your project here--></code>.</p>\n<p>I’ve added a couple of tweaks:</p>\n<ol>\n<li><code>bg-pink</code> in the <code>nav</code> class has been changed to <code>bg-blue</code>, and</li>\n<li>the <code>Navbar</code> title has been changed to <code>My Site</code>.</li>\n</ol>\n<pre><code class=\"markup language-markup\"><!--Main Navigation-->\r\n<header>\r\n <nav class=\"navbar fixed-top navbar-expand-lg navbar-dark bg-blue scrolling-navbar\">\r\n <a class=\"navbar-brand\" href=\"#\"><strong>My Site</strong></a>\r\n <button class=\"navbar-toggler\" type=\"button\" data-toggle=\"collapse\" data-target=\"#navbarSupportedContent\" aria-controls=\"navbarSupportedContent\" aria-expanded=\"false\" aria-label=\"Toggle navigation\">\r\n <span class=\"navbar-toggler-icon\"></span>\r\n </button>\r\n <div class=\"collapse navbar-collapse\" id=\"navbarSupportedContent\">\r\n <ul class=\"navbar-nav mr-auto\">\r\n <li class=\"nav-item active\">\r\n <a class=\"nav-link\" href=\"#\">Home <span class=\"sr-only\">(current)</span></a>\r\n </li>\r\n <li class=\"nav-item\">\r\n <a class=\"nav-link\" href=\"#\">Features</a>\r\n </li>\r\n <li class=\"nav-item\">\r\n <a class=\"nav-link\" href=\"#\">Pricing</a>\r\n </li>\r\n <li class=\"nav-item\">\r\n <a class=\"nav-link\" href=\"#\">Opinions</a>\r\n </li>\r\n </ul>\r\n <ul class=\"navbar-nav nav-flex-icons\">\r\n <li class=\"nav-item\">\r\n <a class=\"nav-link\"><i class=\"fa fa-facebook\"></i></a>\r\n </li>\r\n <li class=\"nav-item\">\r\n <a class=\"nav-link\"><i class=\"fa fa-twitter\"></i></a>\r\n </li>\r\n <li class=\"nav-item\">\r\n <a class=\"nav-link\"><i class=\"fa fa-instagram\"></i></a>\r\n </li>\r\n </ul>\r\n </div>\r\n </nav>\r\n</header>\r\n<!--Main Navigation-->\r\n</code></pre>\n<p>The result:</p>\n<p><img class=\"aligncenter size-large wp-image-160668\" src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508135782mdb-04navbar.png\" alt=\"navigation menu\" width=\"977\" height=\"64\" /></p>\n<h2 id=\"addacarousel\">Add a Carousel</h2>\n<p>I’m not a big fan of carousels but clients usually love them. The <a href=\"https://mdbootstrap.com/javascript/carousel/?utm_source=sitePoint&utm_campaign=sitePoint-MDBFree-sponsoredPost&utm_medium=link&utm_content=documentationLink\" rel=\"nofollow\">MDBootstrap JavaScript / Carousel</a> provides numerous options but we’ll use the <a href=\"https://mdbootstrap.com/javascript/carousel/#basic-example?utm_source=sitePoint&utm_campaign=sitePoint-MDBFree-sponsoredPost&utm_medium=link&utm_content=documentationLink\" rel=\"nofollow\">Basic Example</a> by pasting the HTML immediately after the navigation menu:</p>\n<pre><code class=\"markup language-markup\"><!--Carousel Wrapper-->\r\n<div id=\"carousel-example-2\" class=\"carousel slide carousel-fade\" data-ride=\"carousel\">\r\n <!--Indicators-->\r\n <ol class=\"carousel-indicators\">\r\n <li data-target=\"#carousel-example-2\" data-slide-to=\"0\" class=\"active\"></li>\r\n <li data-target=\"#carousel-example-2\" data-slide-to=\"1\"></li>\r\n <li data-target=\"#carousel-example-2\" data-slide-to=\"2\"></li>\r\n </ol>\r\n <!--/.Indicators-->\r\n <!--Slides-->\r\n <div class=\"carousel-inner\" role=\"listbox\">\r\n <div class=\"carousel-item active\">\r\n <div class=\"view hm-black-light\">\r\n <img class=\"d-block w-100\" src=\"https://mdbootstrap.com/img/Photos/Slides/img%20(68).jpg\" alt=\"First slide\">\r\n <div class=\"mask\"></div>\r\n </div>\r\n <div class=\"carousel-caption\">\r\n <h3 class=\"h3-responsive\">Yeah, so carousels are a bit \"meh\"</h3>\r\n <p>But...</p>\r\n </div>\r\n </div>\r\n <div class=\"carousel-item\">\r\n <!--Mask color-->\r\n <div class=\"view hm-black-strong\">\r\n <img class=\"d-block w-100\" src=\"https://mdbootstrap.com/img/Photos/Slides/img%20(6).jpg\" alt=\"Second slide\">\r\n <div class=\"mask\"></div>\r\n </div>\r\n <div class=\"carousel-caption\">\r\n <h3 class=\"h3-responsive\">your client will love it</h3>\r\n <p>and be amazed by your techical ability</p>\r\n </div>\r\n </div>\r\n <div class=\"carousel-item\">\r\n <!--Mask color-->\r\n <div class=\"view hm-black-slight\">\r\n <img class=\"d-block w-100\" src=\"https://mdbootstrap.com/img/Photos/Slides/img%20(9).jpg\" alt=\"Third slide\">\r\n <div class=\"mask\"></div>\r\n </div>\r\n <div class=\"carousel-caption\">\r\n <h3 class=\"h3-responsive\">Be prepared</h3>\r\n <p>to have money thrown at you!</p>\r\n </div>\r\n </div>\r\n </div>\r\n <!--/.Slides-->\r\n <!--Controls-->\r\n <a class=\"carousel-control-prev\" href=\"#carousel-example-2\" role=\"button\" data-slide=\"prev\">\r\n <span class=\"carousel-control-prev-icon\" aria-hidden=\"true\"></span>\r\n <span class=\"sr-only\">Previous</span>\r\n </a>\r\n <a class=\"carousel-control-next\" href=\"#carousel-example-2\" role=\"button\" data-slide=\"next\">\r\n <span class=\"carousel-control-next-icon\" aria-hidden=\"true\"></span>\r\n <span class=\"sr-only\">Next</span>\r\n </a>\r\n <!--/.Controls-->\r\n</div>\r\n<!--/.Carousel Wrapper-->\r\n</code></pre>\n<p>It’s a lot of code but don’t be afraid to change the image <code>src</code> attributes, <code>h3</code> titles and <code>p</code> paragraph text. You can also add or remove <code><div class=\"carousel-item\"></code> blocks as necessary.</p>\n<p>Save and refresh your page in the browser:</p>\n<p><img class=\"aligncenter size-large wp-image-160670\" src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508135787mdb-05carousel.jpg\" alt=\"carousel\" width=\"976\" height=\"432\" /></p>\n<h2 id=\"addingpagecontent\">Adding Page Content</h2>\n<p>Our page now requires content. It’s best to place content components within a container so there’s a margin to the browser viewport:</p>\n<pre><code class=\"markup language-markup\"><div class=\"container-fluid\">\r\n <!-- page content here -->\r\n</div>\r\n</code></pre>\n<h3 id=\"addafeaturesectiontothepagecontent\">Add a Feature Section to the Page Content</h3>\n<p>MDBootstrap’s <a href=\"https://mdbootstrap.com/sections/features-sections/#v-1?utm_source=sitePoint&utm_campaign=sitePoint-MDBFree-sponsoredPost&utm_medium=link&utm_content=documentationLink\" rel=\"nofollow\">Sections / Features</a> is a good starting point because it describes the essential aspects of a product or service. Copy the <a href=\"https://mdbootstrap.com/sections/features-sections/#v-1?utm_source=sitePoint&utm_campaign=sitePoint-MDBFree-sponsoredPost&utm_medium=link&utm_content=documentationLink\" rel=\"nofollow\">Features v.1 code</a> <strong>within</strong> the container <code><div></code> added above:</p>\n<pre><code class=\"markup language-markup\"><!--Section: Features v.1-->\r\n<section class=\"section feature-box\">\r\n\r\n <!--Section heading-->\r\n <h1 class=\"section-heading pt-4\">Why is it so great?</h1>\r\n <!--Section description-->\r\n <p class=\"section-description lead grey-text\">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam.</p>\r\n\r\n <!--Grid row-->\r\n <div class=\"row features-big\">\r\n\r\n <!--Grid column-->\r\n <div class=\"col-md-4 mb-r\">\r\n <i class=\"fa fa-area-chart red-text\"></i>\r\n <h5 class=\"feature-title\">Analytics</h5>\r\n <p class=\"grey-text\">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Reprehenderit maiores nam, aperiam minima assumenda deleniti hic.</p>\r\n </div>\r\n <!--Grid column-->\r\n\r\n <!--Grid column-->\r\n <div class=\"col-md-4 mb-r\">\r\n <i class=\"fa fa-book cyan-text\"></i>\r\n <h5 class=\"feature-title\">Tutorials</h5>\r\n <p class=\"grey-text\">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Reprehenderit maiores nam, aperiam minima assumenda deleniti hic.</p>\r\n </div>\r\n <!--Grid column-->\r\n\r\n <!--Grid column-->\r\n <div class=\"col-md-4 mb-r\">\r\n <i class=\"fa fa-coffee orange-text\"></i>\r\n <h5 class=\"feature-title\">Relax</h5>\r\n <p class=\"grey-text\">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Reprehenderit maiores nam, aperiam minima assumenda deleniti hic.</p>\r\n </div>\r\n <!--Grid column-->\r\n\r\n </div>\r\n <!--Grid row-->\r\n\r\n</section>\r\n<!--Section: Features v.1-->\r\n</code></pre>\n<p>The result:</p>\n<p><img class=\"aligncenter size-large wp-image-160664\" src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508135776mdb-06features.png\" alt=\"feature section\" width=\"947\" height=\"293\" /></p>\n<h3 id=\"addablockquotetopagecontent\">Add a Blockquote to Page Content</h3>\n<p>The MDBootstrap’s <a href=\"https://mdbootstrap.com/content/typography/?utm_source=sitePoint&utm_campaign=sitePoint-MDBFree-sponsoredPost&utm_medium=link&utm_content=documentationLink\" rel=\"nofollow\">Content / Typography</a> explains a range of text components including titles, paragraphs, and lists. We can use a <a href=\"https://mdbootstrap.com/content/typography/#blockquotes?utm_source=sitePoint&utm_campaign=sitePoint-MDBFree-sponsoredPost&utm_medium=link&utm_content=documentationLink\" rel=\"nofollow\">blockquote section</a> to add an inspirational quote to our page. The code should be placed immediately after feature section and remain within the container <code><div></code>:</p>\n<pre><code class=\"markup language-markup\"><blockquote class=\"blockquote\">\r\n <p class=\"mb-0\">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer posuere erat a ante.</p>\r\n <footer class=\"blockquote-footer\">Someone famous in <cite title=\"Source Title\">Source Title</cite></footer>\r\n</blockquote>\r\n</code></pre>\n<p>Again, you can change the text to whatever you like then save and refresh:</p>\n<p><img class=\"aligncenter size-large wp-image-160667\" src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508135781mdb-07blockquote.png\" alt=\"blockquote\" width=\"947\" height=\"98\" /></p>\n<h3 id=\"addarecentpostssectiontopagecontent\">Add a Recent Posts Section to Page Content</h3>\n<p>MDBootstrap provides a variety of <a href=\"https://mdbootstrap.com/sections/blog/?utm_source=sitePoint&utm_campaign=sitePoint-MDBFree-sponsoredPost&utm_medium=link&utm_content=documentationLink\" rel=\"nofollow\">Blog listing sections</a>. A reasonable choice for our example page is <a href=\"https://mdbootstrap.com/sections/blog/#v-3?utm_source=sitePoint&utm_campaign=sitePoint-MDBFree-sponsoredPost&utm_medium=link&utm_content=documentationLink\" rel=\"nofollow\">Blog Listing v.3</a>. Copy the code immediately after the blockquote within the container <code><div></code>:</p>\n<pre><code class=\"markup language-markup\"><!--Section: Blog v.3-->\r\n<section class=\"section extra-margins pb-3 text-center text-lg-left\">\r\n\r\n <!--Section heading-->\r\n <h2 class=\"section-heading h2 pt-4\">Recent posts</h2>\r\n <!--Section description-->\r\n <p class=\"section-description\">Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>\r\n\r\n <!--Grid row-->\r\n <div class=\"row\">\r\n\r\n <!--Grid column-->\r\n <div class=\"col-lg-4 mb-4\">\r\n <!--Featured image-->\r\n <div class=\"view overlay hm-white-slight z-depth-1-half\">\r\n <img src=\"https://mdbootstrap.com/img/Photos/Others/img (38).jpg\" class=\"img-fluid\" alt=\"First sample image\">\r\n <a>\r\n <div class=\"mask\"></div>\r\n </a>\r\n </div>\r\n </div>\r\n <!--Grid column-->\r\n\r\n <!--Grid column-->\r\n <div class=\"col-lg-7 ml-xl-4 mb-4\">\r\n <!--Excerpt-->\r\n <a href=\"\" class=\"teal-text\"><h6 class=\"pb-1\"><i class=\"fa fa-heart\"></i><strong> Lifestyle </strong></h6></a>\r\n <h4 class=\"mb-3\"><strong>This is title of the news</strong></h4>\r\n <p>Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus id quod maxime placeat facere possimus, omnis voluptas assumenda est, omnis dolor repellendus et aut officiis debitis aut rerum.</p>\r\n <p>by <a><strong>Jessica Clark</strong></a>, 26/08/2016</p>\r\n <a class=\"btn btn-primary btn-sm\">Read more</a>\r\n </div>\r\n <!--Grid column-->\r\n\r\n </div>\r\n <!--Grid row-->\r\n\r\n <hr class=\"mb-5\">\r\n\r\n <!--Grid row-->\r\n <div class=\"row mt-3\">\r\n\r\n <!--Grid column-->\r\n <div class=\"col-lg-4 mb-4\">\r\n <!--Featured image-->\r\n <div class=\"view overlay hm-white-slight z-depth-1-half\">\r\n <img src=\"https://mdbootstrap.com/img/Photos/Others/forest-sm.jpg\" class=\"img-fluid\" alt=\"Second sample image\">\r\n <a>\r\n <div class=\"mask\"></div>\r\n </a>\r\n </div>\r\n </div>\r\n <!--Grid column-->\r\n\r\n <!--Grid column-->\r\n <div class=\"col-lg-7 ml-xl-4 mb-4\">\r\n <!--Excerpt-->\r\n <a href=\"\" class=\"cyan-text\"><h6 class=\"pb-1\"><i class=\"fa fa-plane\"></i><strong> Travels</strong></h6></a>\r\n <h4 class=\"mb-3\"><strong>This is title of the news</strong></h4>\r\n <p>At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident et dolorum fuga.</p>\r\n <p>by <a><strong>Jessica Clark</strong></a>, 24/08/2016</p>\r\n <a class=\"btn btn-primary btn-sm\">Read more</a>\r\n </div>\r\n <!--Grid column-->\r\n\r\n </div>\r\n <!--Grid row-->\r\n\r\n <hr class=\"mb-5\">\r\n\r\n <!--Grid row-->\r\n <div class=\"row\">\r\n\r\n <!--Grid column-->\r\n <div class=\"col-lg-4 mb-4\">\r\n <!--Featured image-->\r\n <div class=\"view overlay hm-white-slight z-depth-1-half\">\r\n <img src=\"https://mdbootstrap.com/img/Photos/Others/img (35).jpg\" class=\"img-fluid\" alt=\"Third sample image\">\r\n <a>\r\n <div class=\"mask\"></div>\r\n </a>\r\n </div>\r\n </div>\r\n <!--Grid column-->\r\n\r\n <!--Grid column-->\r\n <div class=\"col-lg-7 ml-xl-4 mb-4\">\r\n <!--Excerpt-->\r\n <a href=\"\" class=\"brown-text\"><h6 class=\"pb-1\"><i class=\"fa fa-camera\"></i><strong> Photography</strong></h6></a>\r\n <h4 class=\"mb-3\"><strong>This is title of the news</strong></h4>\r\n <p>Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur.</p>\r\n <p>by <a><strong>Jessica Clark</strong></a>, 21/08/2016</p>\r\n <a class=\"btn btn-primary btn-sm\">Read more</a>\r\n </div>\r\n <!--Grid column-->\r\n\r\n </div>\r\n <!--Grid row-->\r\n\r\n</section>\r\n<!--Section: Blog v.3-->\r\n</code></pre>\n<p>Change the titles, text and images to whatever you require then save and refresh:</p>\n<p><img class=\"aligncenter size-large wp-image-160671\" src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508135789mdb-08posts.jpg\" alt=\"blog posts\" width=\"938\" height=\"377\" /></p>\n<h2 id=\"addafooter\">Add a Footer</h2>\n<p>A range of page footers can be found in MDBootstrap’s <a href=\"https://mdbootstrap.com/components/bootstrap-footer/?utm_source=sitePoint&utm_campaign=sitePoint-MDBFree-sponsoredPost&utm_medium=link&utm_content=documentationLink\" rel=\"nofollow\">Components / Footer</a> section. I’ve chosen the <a href=\"https://mdbootstrap.com/components/bootstrap-footer/#advanced?utm_source=sitePoint&utm_campaign=sitePoint-MDBFree-sponsoredPost&utm_medium=link&utm_content=documentationLink\" rel=\"nofollow\">Advanced Footer</a> – the code must be placed immediately before the closing <code><!-- /Start your project here--></code> and be careful <strong>not</strong> to place it within the content container <code><div></code>:</p>\n<pre><code class=\"markup language-markup\"><!--Footer-->\r\n<footer class=\"page-footer center-on-small-only stylish-color-dark\">\r\n\r\n <!--Footer Links-->\r\n <div class=\"container\">\r\n <div class=\"row\">\r\n\r\n <!--First column-->\r\n <div class=\"col-md-4\">\r\n <h5 class=\"title mb-4 mt-3 font-bold\">Footer Content</h5>\r\n <p>Here you can use rows and columns here to organize your footer content. Lorem ipsum dolor sit\r\n amet, consectetur adipisicing elit.</p>\r\n </div>\r\n <!--/.First column-->\r\n\r\n <hr class=\"clearfix w-100 d-md-none\">\r\n\r\n <!--Second column-->\r\n <div class=\"col-md-2 mx-auto\">\r\n <h5 class=\"title mb-4 mt-3 font-bold\">Links</h5>\r\n <ul>\r\n <li><a href=\"#!\">Link 1</a></li>\r\n <li><a href=\"#!\">Link 2</a></li>\r\n <li><a href=\"#!\">Link 3</a></li>\r\n <li><a href=\"#!\">Link 4</a></li>\r\n </ul>\r\n </div>\r\n <!--/.Second column-->\r\n\r\n <hr class=\"clearfix w-100 d-md-none\">\r\n\r\n <!--Third column-->\r\n <div class=\"col-md-2 mx-auto\">\r\n <h5 class=\"title mb-4 mt-3 font-bold\">Links</h5>\r\n <ul>\r\n <li><a href=\"#!\">Link 1</a></li>\r\n <li><a href=\"#!\">Link 2</a></li>\r\n <li><a href=\"#!\">Link 3</a></li>\r\n <li><a href=\"#!\">Link 4</a></li>\r\n </ul>\r\n </div>\r\n <!--/.Third column-->\r\n\r\n <hr class=\"clearfix w-100 d-md-none\">\r\n\r\n <!--Fourth column-->\r\n <div class=\"col-md-2 mx-auto\">\r\n <h5 class=\"title mb-4 mt-3 font-bold \">Links</h5>\r\n <ul>\r\n <li><a href=\"#!\">Link 1</a></li>\r\n <li><a href=\"#!\">Link 2</a></li>\r\n <li><a href=\"#!\">Link 3</a></li>\r\n <li><a href=\"#!\">Link 4</a></li>\r\n </ul>\r\n </div>\r\n <!--/.Fourth column-->\r\n </div>\r\n </div>\r\n <!--/.Footer Links-->\r\n\r\n <hr>\r\n\r\n <!--Call to action-->\r\n <div class=\"call-to-action\">\r\n <ul>\r\n <li>\r\n <h5 class=\"mb-1\">Register for free</h5>\r\n </li>\r\n <li><a href=\"\" class=\"btn btn-danger btn-rounded\">Sign up!</a></li>\r\n </ul>\r\n </div>\r\n <!--/.Call to action-->\r\n\r\n <hr>\r\n\r\n <!--Social buttons-->\r\n <div class=\"social-section text-center\">\r\n <ul>\r\n\r\n <li><a class=\"btn-floating btn-sm btn-fb\"><i class=\"fa fa-facebook\"> </i></a></li>\r\n <li><a class=\"btn-floating btn-sm btn-tw\"><i class=\"fa fa-twitter\"> </i></a></li>\r\n <li><a class=\"btn-floating btn-sm btn-gplus\"><i class=\"fa fa-google-plus\"> </i></a></li>\r\n <li><a class=\"btn-floating btn-sm btn-li\"><i class=\"fa fa-linkedin\"> </i></a></li>\r\n <li><a class=\"btn-floating btn-sm btn-dribbble\"><i class=\"fa fa-dribbble\"> </i></a></li>\r\n\r\n </ul>\r\n </div>\r\n <!--/.Social buttons-->\r\n\r\n <!--Copyright-->\r\n <div class=\"footer-copyright\">\r\n <div class=\"container-fluid\">\r\n © 2017 Copyright: <a href=\"https://www.sitepoint.com\"> SitePoint.com </a>\r\n </div>\r\n </div>\r\n <!--/.Copyright-->\r\n\r\n</footer>\r\n<!--/.Footer-->\r\n</code></pre>\n<p>Change the links and text as necessary then save and refresh:</p>\n<p><img class=\"aligncenter size-full wp-image-160663\" src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508135774mdb-09footer.png\" alt=\"blog posts\" width=\"977\" height=\"461\" /></p>\n<p>Our page is now complete. The whole creation took no more than a few minutes — although remember to spare some time to change the default text and upload your creation to a suitable web host!</p>\n<h2 id=\"moreinformationaboutmdbootstrap\">More Information About MDBootstrap</h2>\n<p>For more information, refer to <a href=\"https://mdbootstrap.com/material-design-for-bootstrap/?utm_source=sitePoint&utm_campaign=sitePoint-MDBFree-sponsoredPost&utm_medium=link&utm_content=documentationLink\" rel=\"nofollow\">Material Design for Bootstrap </a> and watch the five-minute “Quick Start” tutorial. A number of free tutorials are also available including:</p>\n<ul>\n<li><a href=\"https://mdbootstrap.com/bootstrap-tutorial/?utm_source=sitePoint&utm_campaign=sitePoint-MDBFree-sponsoredPost&utm_medium=link&utm_content=documentationLink\" rel=\"nofollow\">a Bootstrap 4 guide</a></li>\n<li><a href=\"https://mdbootstrap.com/wordpress-tutorial/?utm_source=sitePoint&utm_campaign=sitePoint-MDBFree-sponsoredPost&utm_medium=link&utm_content=documentationLink\" rel=\"nofollow\">integration with WordPress</a>, and</li>\n<li><a href=\"https://mdbootstrap.com/marketing-automation-tutorial/?utm_source=sitePoint&utm_campaign=sitePoint-MDBFree-sponsoredPost&utm_medium=link&utm_content=documentationLink\" rel=\"nofollow\">marketing automation</a>.</li>\n</ul>\n<p>The 400 components in the <a href=\"https://mdbootstrap.com/getting-started/?utm_source=sitePoint&utm_campaign=sitePoint-MDBFree-sponsoredPost&utm_medium=link&utm_content=documentationLink\" rel=\"nofollow\">free edition</a> provides a no-obligation way to assess the system before you upgrade to the <a href=\"https://mdbootstrap.com/product/material-design-for-bootstrap-pro/?utm_source=sitePoint&utm_campaign=sitePoint-MDBFree-sponsoredPost&utm_medium=link&utm_content=mdbProLink\" rel=\"nofollow\">commercial PRO edition</a>.</p>\n<p>🚨 SitePoint readers can get 10% off the price of PRO by using the code <strong>sitepoint</strong> at the checkout! 🚨</p>\n","protected":false},"excerpt":{"rendered":"<p class=\"wp-special\"><em>This article was sponsored by <a href=\"https://mdbootstrap.com/\" rel=\"nofollow\">MDBootstrap</a>. Thank you for supporting the partners who make SitePoint possible.</em></p>\n<p>As a SitePoint reader, you’re undoubtedly interested in creating bleeding-edge, sophisticated web sites and applications. You may not write everything from scratch, but you want a deep understanding of the code. You need nothing more than a text editor to build your next award-winning masterpiece.</p>\n<p>Unfortunately, working life isn’t always so simple. You could be taking your first steps toward becoming a web development ninja. Your boss may want something completed within hours rather than days. Your client could be at the lower end of the budgetary spectrum. You need something practical developed quickly and painlessly within a few hours.</p>\n<p>Many would consider a CMS such as WordPress. It’s a good option but it can be overkill and take too much time. Novice coders may be daunted by hosting requirements, PHP set-ups, MySQL database creation and the WordPress ecosystem. Even if your initial installation goes smoothly, you need to locate, install, configure and use appropriate themes and plugins.</p>\n<h2 id=\"enterthemdbootstrapuikit\">Enter the MDBootstrap UI Kit</h2>\n<p>Fortunately, there is an easier alternative. <a href=\"https://mdbootstrap.com/\" rel=\"nofollow\">Material Design for Bootstrap (mdbootstrap.com)</a> provides a set of slick, responsive page templates, layouts, components and widgets to rapidly build web pages. There’s no complication or fuss: <em>you just copy and paste code into one or more HTML files</em>. It’ll help if you have a basic understanding of client-side web development but even those with a rudimentary knowledge of HTML can build an attractive page within minutes.</p>\n<p>The <a href=\"https://mdbootstrap.com/getting-started/\" rel=\"nofollow\">free edition</a> has more than 400 components to choose from. The <a href=\"https://mdbootstrap.com/product/mdb-big-bundle/\" rel=\"nofollow\">commercial PRO edition</a> contains more than 2,000 components with additional templates, tutorials, tools, and support. Both editions come in <a href=\"https://mdbootstrap.com/\" rel=\"nofollow\">jQuery</a>, <a href=\"https://mdbootstrap.com/angular/\" rel=\"nofollow\">Angular 4</a>, or <a href=\"https://mdbootstrap.com/react/\" rel=\"nofollow\">React</a> flavors so you can select the most appropriate framework <em>(if in doubt, stick with jQuery, which has a shallower learning curve and legacy browser support)</em>. If necessary, your resulting page templates can be <a href=\"https://mdbootstrap.com/wordpress-tutorial/\" rel=\"nofollow\">imported into WordPress</a> so your client can add and update content.</p>\n<p>Install MDBootstrap by downloading and extracting the ZIP file to an appropriate location on your PC. You can use any folder since most pages will open in a browser directly from your file system. That said, I’d recommend you place them in a web server folder — especially if you intend to use JavaScript-powered components. If you don’t have a server installed, a quick option is <a href=\"https://www.npmjs.com/package/http-server\" rel=\"nofollow\">http-server for Node.js</a> (which exposes the current folder as a web root) or an all-in-one package such as <a href=\"https://www.apachefriends.org/\" rel=\"nofollow\">XAMPP</a>. Alternatively, you may be able to upload the files to your web host and edit there using a compatible editor such as <a href=\"https://codeanywhere.com/\" rel=\"nofollow\">codeanywhere</a>.</p>\n<h2 id=\"yourfirstmdbootstrappage\">Your First MDBootstrap Page</h2>\n<p>Open <code>index.html</code> in your web browser and you’ll see a home page with a welcome message:</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508135777mdb-01initial.png\" alt=\"initial welcome message\" width=\"813\" height=\"234\" class=\"aligncenter size-large wp-image-160665\" /></p>\n<p>Now open <code>index.html</code> in your text editor or IDE of choice (perhaps the fabulous and free <a href=\"https://code.visualstudio.com/\" rel=\"nofollow\">VS Code</a> or <a href=\"https://atom.io/\" rel=\"nofollow\">Atom</a>). Delete the lines of HTML between:</p>\n<pre><code class=\"markup language-markup\"><!-- Start your project here-->\r\n</code></pre>\n<p>and</p>\n<pre><code class=\"markup language-markup\"><!-- /Start your project here-->\r\n</code></pre>\n<p>then replace them with:</p>\n<pre><code class=\"markup language-markup\"><div class=\"container-fluid\">\r\n\r\n <h1>Welcome</h1>\r\n <p>This is my first MDBootstrap page.</p>\r\n\r\n</div>\r\n</code></pre>\n<p>The code defines a container which provides a margin and responds to the browser width. It contains a title and paragraph:</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508135779mdb-02first.png\" alt=\"your first page\" width=\"273\" height=\"76\" class=\"aligncenter size-large wp-image-160666\" /></p>\n<h2 id=\"copyinghtmlandcss\">Copying HTML and CSS</h2>\n<p>You’re now ready to insert your own components. Head over to <a href=\"https://mdbootstrap.com/\" rel=\"nofollow\">mdbootstrap.com</a> and click the menu icon at the top-left of the page. A long list of categorized components can be selected.</p>\n<p>Most components require you to insert HTML into your page. Some also require additional CSS styles which should be copied and pasted into the (initially empty) <code>css/style.css</code> file. A link to this stylesheet is already provided in the HTML <code><head></code>:</p>\n<pre><code class=\"markup language-markup\"><link href=\"css/style.css\" rel=\"stylesheet\">\r\n</code></pre>\n<h2 id=\"creatinganadvancedlayout\">Creating an Advanced Layout</h2>\n<p>The following sections describe how to create a more advanced page:</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508135785mdb-03advanced-407x1024.jpg\" alt=\"advanced page\" width=\"407\" height=\"1024\" class=\"aligncenter size-large wp-image-160669\" /></p>\n<p>Make sure you revert back to an empty page by removing the code between:</p>\n<pre><code class=\"markup language-markup\"><!-- Start your project here-->\r\n</code></pre>\n<p>and</p>\n<pre><code class=\"markup language-markup\"><!-- /Start your project here-->\r\n</code></pre>\n<h2 id=\"addnavigation\">Add Navigation</h2>\n<p>The <a href=\"https://mdbootstrap.com/layout/bootstrap-navigation/\" rel=\"nofollow\">MDBootstrap Layout / Navigation</a> provides a variety of options which collapse to hamburger menus when space is limited. The <a href=\"https://mdbootstrap.com/layout/bootstrap-navigation/#r-f-n\" rel=\"nofollow\">Regular Fixed Navbar</a> HTML can be copied into the page immediately after <code><!-- Start your project here--></code>.</p>\n<p>I’ve added a couple of tweaks:</p>\n<ol>\n<li><code>bg-pink</code> in the <code>nav</code> class has been changed to <code>bg-blue</code>, and</li>\n<li>the <code>Navbar</code> title has been changed to <code>My Site</code>.</li>\n</ol>\n<pre><code class=\"markup language-markup\"><!--Main Navigation-->\r\n<header>\r\n <nav class=\"navbar fixed-top navbar-expand-lg navbar-dark bg-blue scrolling-navbar\">\r\n <a class=\"navbar-brand\" href=\"#\"><strong>My Site</strong></a>\r\n <button class=\"navbar-toggler\" type=\"button\" data-toggle=\"collapse\" data-target=\"#navbarSupportedContent\" aria-controls=\"navbarSupportedContent\" aria-expanded=\"false\" aria-label=\"Toggle navigation\">\r\n <span class=\"navbar-toggler-icon\"></span>\r\n </button>\r\n <div class=\"collapse navbar-collapse\" id=\"navbarSupportedContent\">\r\n <ul class=\"navbar-nav mr-auto\">\r\n <li class=\"nav-item active\">\r\n <a class=\"nav-link\" href=\"#\">Home <span class=\"sr-only\">(current)</span></a>\r\n </li>\r\n <li class=\"nav-item\">\r\n <a class=\"nav-link\" href=\"#\">Features</a>\r\n </li>\r\n <li class=\"nav-item\">\r\n <a class=\"nav-link\" href=\"#\">Pricing</a>\r\n </li>\r\n <li class=\"nav-item\">\r\n <a class=\"nav-link\" href=\"#\">Opinions</a>\r\n </li>\r\n </ul>\r\n <ul class=\"navbar-nav nav-flex-icons\">\r\n <li class=\"nav-item\">\r\n <a class=\"nav-link\"><i class=\"fa fa-facebook\"></i></a>\r\n </li>\r\n <li class=\"nav-item\">\r\n <a class=\"nav-link\"><i class=\"fa fa-twitter\"></i></a>\r\n </li>\r\n <li class=\"nav-item\">\r\n <a class=\"nav-link\"><i class=\"fa fa-instagram\"></i></a>\r\n </li>\r\n </ul>\r\n </div>\r\n </nav>\r\n</header>\r\n<!--Main Navigation-->\r\n</code></pre>\n<p>The result:</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508135782mdb-04navbar.png\" alt=\"navigation menu\" width=\"977\" height=\"64\" class=\"aligncenter size-large wp-image-160668\" /></p>\n<h2 id=\"addacarousel\">Add a Carousel</h2>\n<p>I’m not a big fan of carousels but clients usually love them. The <a href=\"https://mdbootstrap.com/javascript/carousel/\" rel=\"nofollow\">MDBootstrap JavaScript / Carousel</a> provides numerous options but we’ll use the <a href=\"https://mdbootstrap.com/javascript/carousel/#basic-example\" rel=\"nofollow\">Basic Example</a> by pasting the HTML immediately after the navigation menu:</p>\n<pre><code class=\"markup language-markup\"><!--Carousel Wrapper-->\r\n<div id=\"carousel-example-2\" class=\"carousel slide carousel-fade\" data-ride=\"carousel\">\r\n <!--Indicators-->\r\n <ol class=\"carousel-indicators\">\r\n <li data-target=\"#carousel-example-2\" data-slide-to=\"0\" class=\"active\"></li>\r\n <li data-target=\"#carousel-example-2\" data-slide-to=\"1\"></li>\r\n <li data-target=\"#carousel-example-2\" data-slide-to=\"2\"></li>\r\n </ol>\r\n <!--/.Indicators-->\r\n <!--Slides-->\r\n <div class=\"carousel-inner\" role=\"listbox\">\r\n <div class=\"carousel-item active\">\r\n <div class=\"view hm-black-light\">\r\n <img class=\"d-block w-100\" src=\"https://mdbootstrap.com/img/Photos/Slides/img%20(68).jpg\" alt=\"First slide\">\r\n <div class=\"mask\"></div>\r\n </div>\r\n <div class=\"carousel-caption\">\r\n <h3 class=\"h3-responsive\">Yeah, so carousels are a bit \"meh\"</h3>\r\n <p>But...</p>\r\n </div>\r\n </div>\r\n <div class=\"carousel-item\">\r\n <!--Mask color-->\r\n <div class=\"view hm-black-strong\">\r\n <img class=\"d-block w-100\" src=\"https://mdbootstrap.com/img/Photos/Slides/img%20(6).jpg\" alt=\"Second slide\">\r\n <div class=\"mask\"></div>\r\n </div>\r\n <div class=\"carousel-caption\">\r\n <h3 class=\"h3-responsive\">your client will love it</h3>\r\n <p>and be amazed by your techical ability</p>\r\n </div>\r\n </div>\r\n <div class=\"carousel-item\">\r\n <!--Mask color-->\r\n <div class=\"view hm-black-slight\">\r\n <img class=\"d-block w-100\" src=\"https://mdbootstrap.com/img/Photos/Slides/img%20(9).jpg\" alt=\"Third slide\">\r\n <div class=\"mask\"></div>\r\n </div>\r\n <div class=\"carousel-caption\">\r\n <h3 class=\"h3-responsive\">Be prepared</h3>\r\n <p>to have money thrown at you!</p>\r\n </div>\r\n </div>\r\n </div>\r\n <!--/.Slides-->\r\n <!--Controls-->\r\n <a class=\"carousel-control-prev\" href=\"#carousel-example-2\" role=\"button\" data-slide=\"prev\">\r\n <span class=\"carousel-control-prev-icon\" aria-hidden=\"true\"></span>\r\n <span class=\"sr-only\">Previous</span>\r\n </a>\r\n <a class=\"carousel-control-next\" href=\"#carousel-example-2\" role=\"button\" data-slide=\"next\">\r\n <span class=\"carousel-control-next-icon\" aria-hidden=\"true\"></span>\r\n <span class=\"sr-only\">Next</span>\r\n </a>\r\n <!--/.Controls-->\r\n</div>\r\n<!--/.Carousel Wrapper-->\r\n</code></pre>\n<p>It’s a lot of code but don’t be afraid to change the image <code>src</code> attributes, <code>h3</code> titles and <code>p</code> paragraph text. You can also add or remove <code><div class=\"carousel-item\"></code> blocks as necessary.</p>\n<p>Save and refresh your page in the browser:</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508135787mdb-05carousel.jpg\" alt=\"carousel\" width=\"976\" height=\"432\" class=\"aligncenter size-large wp-image-160670\" /></p>\n<h2 id=\"addingpagecontent\">Adding Page Content</h2>\n<p>Our page now requires content. It’s best to place content components within a container so there’s a margin to the browser viewport:</p>\n<pre><code class=\"markup language-markup\"><div class=\"container-fluid\">\r\n <!-- page content here -->\r\n</div>\r\n</code></pre>\n<h3 id=\"addafeaturesectiontothepagecontent\">Add a Feature Section to the Page Content</h3>\n<p>MDBootstrap’s <a href=\"https://mdbootstrap.com/sections/features-sections/#v-1\" rel=\"nofollow\">Sections / Features</a> is a good starting point because it describes the essential aspects of a product or service. Copy the <a href=\"https://mdbootstrap.com/sections/features-sections/#v-1\" rel=\"nofollow\">Features v.1 code</a> <strong>within</strong> the container <code><div></code> added above:</p>\n","protected":false},"author":515,"featured_media":161047,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[6131],"tags":[105,9553,5932,6298],"_links":{"self":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/posts/160660"}],"collection":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/posts"}],"about":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/types/post"}],"author":[{"embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/users/515"}],"replies":[{"embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/comments?post=160660"}],"version-history":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/posts/160660/revisions"}],"wp_featuredmedia":[{"embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/media/161047"}],"wp_attachment":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/media?parent=160660"}],"wp_term":[{"taxonomy":"category","embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/categories?post=160660"},{"taxonomy":"post_tag","embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/tags?post=160660"}],"curies":[{"name":"wp","href":"https://api.w.org/{rel}","templated":true}]}}
{"index":{"_index":"blogs","_id":160848,"_type":"default"}}
{"id":160848,"date":"2017-10-24T09:00:44","date_gmt":"2017-10-24T16:00:44","guid":{"rendered":"https://www.sitepoint.com/?p=160848"},"modified":"2017-10-22T23:27:32","modified_gmt":"2017-10-23T06:27:32","slug":"common-analytics-pitfalls-to-watch-out-for","status":"publish","type":"post","link":"https://www.sitepoint.com/common-analytics-pitfalls-to-watch-out-for/","title":{"rendered":"11 Common Analytics Pitfalls to Watch Out For"},"content":{"rendered":"<p><em>The following is a short extract from our book, <a href=\"https://www.sitepoint.com/premium/books/researching-ux-analytics\">Researching UX: Analytics</a>, written by Luke Hay. It’s the ultimate guide to using analytics for improved user experience. SitePoint Premium members get access with their membership, or you can buy a copy in stores worldwide.</em></p>\n<p>When you first start analyzing data, it’s easy to make mistakes, particularly if you’re new to analytics. Don’t let that put you off, though! This section lists some of the main pitfalls, and how they’re best avoided—to ensure your analysis paints a true picture of user behavior.</p>\n<h3 id=\"confusing-visits-and-views\">Confusing Visits and Views</h3>\n<p>Different analytics tools will use different terminology to describe the same thing. For rookie analysts, this can cause confusion, and can mean that the wrong data is reported. Even within the same tool, terminology can be confusing. One of the most common mistakes people make is to confuse visits and views.</p>\n<p>A <strong>visit</strong> (now known as a <strong>session</strong> in Google Analytics) generally describes a group of interactions one user takes within a given time frame on your website. A <strong>view</strong> (or “pageview” in some tools) describes a view of a page on your site that is tracked by the analytics tracking code.</p>\n<p>These are two entirely different things, but visits and views are sometimes used interchangeably when people talk about their analytics. As you can imagine, this can cause problems for analysts, as reports will become inaccurate. Make sure you understand the terminology, so that you know what you’re reporting on. (See the Google Analytics glossary at the end of this book if you’re unsure.)</p>\n<h3 id=\"obsessing-over-visits-and-views\">Obsessing over Visits and Views</h3>\n<p>When it comes to analyzing your data, you need to make sure you’re analyzing the most important areas. A very common mistake people make is to focus purely on visits and views. Because you’re a UXer, I know I don’t need to convince you that there’s more to a website than just a lot of people visiting it! You may still find yourself under pressure, though, to increase page views or even visits. Leave this side of things to marketers, and focus your efforts on the numbers that relate to user experience. </p>\n<h3 id=\"getting-drawn-into-the-numbers\">Getting Drawn into the Numbers</h3>\n<p>Quantitative data is all about numbers. If your account is set up correctly, the numbers don’t lie! Despite this, you need to make sure you don’t forget what the numbers actually represent: real users. </p>\n<p>As stated previously, the numbers will tell you what happened, not why, and this is why it’s important not to forget to ask why. You’ll need to look beyond the numbers and consider their context. Make sure you don’t fall into the trap of just reporting what has happened: be sure to consider the bigger picture and think about what the numbers mean for the user experience of your website. </p>\n<p>This is where you’ll need to bring in the qualitative methods we touched on previously. You can often use analytics to find a problem, and user research methods to solve it. </p>\n<h3 id=\"thinking-low-numbers-are-always-bad\">Thinking Low Numbers Are Always Bad</h3>\n<p>One side effect of getting drawn into the numbers is that you automatically consider low numbers, or a drop in numbers, to be bad. While a drop in purchases is likely to be a bad thing, a reduction in the time users spend on particular pages, for example, could be good <em>or</em> bad. </p>\n<p>If you’ve redesigned the home page on a website and the time people are spending on it drops, this could be due to the improved efficiency of your design. It may be that people are able to navigate more quickly to areas of interest to them. Once again, context is key here. Work out what any drops actually mean for the website as a whole, rather than assuming they’re always going to be negative. </p>\n<h3 id=\"confusing-correlation-with-causation\">Confusing Correlation with Causation</h3>\n<p>Just because something happens to your analytics at the same time as you make a change to the website doesn’t mean the two are connected. If you notice changes to your analytics after making a change, you need to be sure it’s not a coincidence and that the two are connected. </p>\n<p>You’re likely to have to delve a little deeper into your reports to prove that the rise in conversion rate was due to your great new design. This is covered in more detail in Chapter 6, but it’s something you should be aware of before you take credit (or blame!) for any sizable shifts in your reporting data. </p>\n<p>The graph below, taken from <a href=\"http://tylervigen.com/spurious-correlations\">tylervigen.com</a>, shows a correlation of close to 95% for cheese consumption and number of people who died by becoming tangled in their bed sheets:</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508422161correlation.png\" alt=\"correlation between heese consumption and death my becoming entangled in bedsheets\" width=\"945\" height=\"469\" class=\"aligncenter size-full wp-image-160851\" /></p>\n<p>There’s also a strong correlation between ice cream sales and drownings at sea, as both go up in the summer. Only an analyst severely lacking common sense would say that ice cream causes drowning, though!</p>\n<p>The correlation versus causation issue is probably the most prolific mistake I see people make when analyzing data. When it comes to website analytics, one example of this might be where data shows that people who use site search covert 50% more than those who don’t. This could convince UXers to encourage more people to use the site search. However, the more likely correlation is that people who use the site search are a more engaged audience than the average users, and also have a better idea of what they’re looking for—meaning that they naturally have higher conversion rates.</p>\n<p>Combining quant and qual (and sometimes your own common sense) will help ensure you don’t fall into the trap of confusing correlation and causation. Split testing is also a great way to determine true causation, and will help to protect against drawing incorrect conclusions from your data. We’ll cover split testing more in Chapter 6.</p>\n<h3 id=\"grouping-all-visits-together\">Grouping All Visits Together</h3>\n<p>As UXers, we know that different people use websites in different ways. We also know that the same person is likely to use a website differently when using different devices, or even using the same website at different times of the day. We need to include these considerations of user behavior in our quantitative analysis.</p>\n<p>If a website has a conversion rate of 5%, this tells us one story. If we break that figure down, though, and see that the conversion rate is 10% for desktop users and only 1% for mobile users, that tells a different story, and gives a good indication of where we should focus our UX efforts! </p>\n<p>Segmenting users is key to understanding how a website is performing. We’ll cover segmentation in more detail later in Chapter 3.</p>\n<h3 id=\"analyzing-too-broadly\">Analyzing Too Broadly</h3>\n<p>With a wealth of data available, knowing where to start analyzing it all can be difficult. When starting a new project, you might want to have a quick, top-level assessment of the available data. But useful insight comes from digging deeper. </p>\n<p>Looking at “headline” figures may give an overall indication of a website’s current performance, but it’s unlikely to give the information we need to improve the UX. Where possible, it’s best to approach your analytics with a goal in mind. This will help focus your efforts, and should help you avoid feeling overwhelmed by the sheer amount of data available. The chapters of this book relate to current UX goals, and are designed to help you approach data analysis in the right way.</p>\n<p>The number of visits (or “sessions”) a website receives is often a figure that people focus in on. This metric tells us little about a website’s performance, though, as the purpose of most websites is to do more than just act as a destination for users. It’s far more important to know how users are engaging with individual pages, and how many of those pages are converting. I’d much rather have a website with 1,000 visitors a month and a conversion rate of 10% than a website with 5,000 visitors a month and a conversion rate of 1%, wouldn’t you?</p>\n<h3 id=\"focusing-on-numbers-rather-than-trends\">Focusing on Numbers Rather than Trends</h3>\n<p>It can be tempting to look at numbers and make a judgement about whether they’re “good” or “bad”. One question I often get asked during my training sessions is “What’s a good average visit duration?” There isn’t a simple answer to this question. It will depend on your website and what you’re trying to achieve. What’s seen as good for one website might be seen as terrible for another. </p>\n<p>It’s important to look at whether your key metrics are increasing or decreasing over time. You might also want to set targets to give yourself something to aim for. Just looking at recent figures in isolation tells you very little. In short, don’t worry so much about the numbers; worry more about whether they’re going up or down, and how that relates to the UX goals you’ve set.</p>\n<p>Remember, though: it’s all about context. Big increases or drops in metrics, or particularly high or low metrics, need to be considered in relation to what’s happening elsewhere on the website or app. For example, if product-page views dropped by 2% over three months, you may not think much of it, but if all other pages had an increase in views of 30% over the same period, suddenly this 2% drop looks like something worth investigating.</p>\n<h3 id=\"including-bot-or-spam-traffic\">Including Bot or Spam Traffic</h3>\n<p>Certain types of traffic can skew your analytics data if you’re not careful. You only want to record visits from real users, and not artificial “bot” traffic. </p>\n<p>Search engines use bots to crawl websites and index the web so they can return relevant search results to users. Bots used by all the major search engines don’t show up in most analytics tools, and you wouldn’t want to block these bots from crawling your website. You do, however, want to block bots that artificially inflate your analytics numbers.</p>\n<p>The amount of bots that execute JavaScript is steadily increasing. Bots now frequently view more than just one page on your website, and some of them even convert on your analytics goals. As bots become smarter, you also need to become smarter, to ensure this traffic doesn’t cloud your judgement when you make important business decisions based on the data in your analytics platform.</p>\n<p>The Fresh Egg blog provides a useful guide on how to spot, and block, spam traffic from your analytics tool in its article “<a href=\"http://www.freshegg.co.uk/blog/analytics/how-to-deal-with-bot-traffic-in-your-google-analytics\">How to Deal With Bot Traffic in Your Google Analytics</a>”.</p>\n<h3 id=\"not-customizing-your-setup\">Not Customizing Your Setup</h3>\n<p>Standard reports in some analytics tools can be really detailed and will provide you with a lot of useful information. But, as mentioned earlier, the standard reporting setup will only get you so far. Each website works differently, so don’t take a one-size-fits-all approach to your analytics. Instead, customize your setup to make sure you get the data you need.</p>\n<h3 id=\"not-generating-actionable-takeaways\">Not Generating Actionable Takeaways</h3>\n<p>You can get a lot of information from your analytics package, and you can present this as important-looking reports and really impress people. What’s more important, however, is coming away from your analysis with actionable next steps based on the data. </p>\n<p>Spotting trends and uncovering potential problems is only doing half the job! If you notice that tablet users are viewing considerably fewer pages than their desktop counterparts, what does this mean? What are you proposing to do about it? While you won’t get an answer about how to fix a problem from your analytics, you should be able to propose your next step. Perhaps the fact that tablet users are seemingly less engaged than desktop users will lead you to do some usability testing on tablets? Or maybe you think you should do additional user research to find out the context in which your tablet users are visiting your website? Whatever you decide, it’s important that you do decide to do something. Analyzing the numbers is just the start; make sure you follow that up with action! </p>\n<p>Your analytics data can also help you prioritize those next steps, as it can help quantify the volume of lost visitors, or sales, or something else, caused by each issue you’ve spotted.</p>\n","protected":false},"excerpt":{"rendered":"<p><em>The following is a short extract from our book, <a href=\"https://www.sitepoint.com/premium/books/researching-ux-analytics\">Researching UX: Analytics</a>, written by Luke Hay. It’s the ultimate guide to using analytics for improved user experience. SitePoint Premium members get access with their membership, or you can buy a copy in stores worldwide.</em></p>\n<p>When you first start analyzing data, it’s easy to make mistakes, particularly if you’re new to analytics. Don’t let that put you off, though! This section lists some of the main pitfalls, and how they’re best avoided—to ensure your analysis paints a true picture of user behavior.</p>\n<h3 id=\"confusing-visits-and-views\">Confusing Visits and Views</h3>\n<p>Different analytics tools will use different terminology to describe the same thing. For rookie analysts, this can cause confusion, and can mean that the wrong data is reported. Even within the same tool, terminology can be confusing. One of the most common mistakes people make is to confuse visits and views.</p>\n<p>A <strong>visit</strong> (now known as a <strong>session</strong> in Google Analytics) generally describes a group of interactions one user takes within a given time frame on your website. A <strong>view</strong> (or “pageview” in some tools) describes a view of a page on your site that is tracked by the analytics tracking code.</p>\n<p>These are two entirely different things, but visits and views are sometimes used interchangeably when people talk about their analytics. As you can imagine, this can cause problems for analysts, as reports will become inaccurate. Make sure you understand the terminology, so that you know what you’re reporting on. (See the Google Analytics glossary at the end of this book if you’re unsure.)</p>\n<h3 id=\"obsessing-over-visits-and-views\">Obsessing over Visits and Views</h3>\n<p>When it comes to analyzing your data, you need to make sure you’re analyzing the most important areas. A very common mistake people make is to focus purely on visits and views. Because you’re a UXer, I know I don’t need to convince you that there’s more to a website than just a lot of people visiting it! You may still find yourself under pressure, though, to increase page views or even visits. Leave this side of things to marketers, and focus your efforts on the numbers that relate to user experience. </p>\n<h3 id=\"getting-drawn-into-the-numbers\">Getting Drawn into the Numbers</h3>\n<p>Quantitative data is all about numbers. If your account is set up correctly, the numbers don’t lie! Despite this, you need to make sure you don’t forget what the numbers actually represent: real users. </p>\n<p>As stated previously, the numbers will tell you what happened, not why, and this is why it’s important not to forget to ask why. You’ll need to look beyond the numbers and consider their context. Make sure you don’t fall into the trap of just reporting what has happened: be sure to consider the bigger picture and think about what the numbers mean for the user experience of your website. </p>\n<p>This is where you’ll need to bring in the qualitative methods we touched on previously. You can often use analytics to find a problem, and user research methods to solve it. </p>\n<h3 id=\"thinking-low-numbers-are-always-bad\">Thinking Low Numbers Are Always Bad</h3>\n<p>One side effect of getting drawn into the numbers is that you automatically consider low numbers, or a drop in numbers, to be bad. While a drop in purchases is likely to be a bad thing, a reduction in the time users spend on particular pages, for example, could be good <em>or</em> bad. </p>\n<p>If you’ve redesigned the home page on a website and the time people are spending on it drops, this could be due to the improved efficiency of your design. It may be that people are able to navigate more quickly to areas of interest to them. Once again, context is key here. Work out what any drops actually mean for the website as a whole, rather than assuming they’re always going to be negative. </p>\n<h3 id=\"confusing-correlation-with-causation\">Confusing Correlation with Causation</h3>\n<p>Just because something happens to your analytics at the same time as you make a change to the website doesn’t mean the two are connected. If you notice changes to your analytics after making a change, you need to be sure it’s not a coincidence and that the two are connected. </p>\n<p>You’re likely to have to delve a little deeper into your reports to prove that the rise in conversion rate was due to your great new design. This is covered in more detail in Chapter 6, but it’s something you should be aware of before you take credit (or blame!) for any sizable shifts in your reporting data. </p>\n<p>The graph below, taken from <a href=\"http://tylervigen.com/spurious-correlations\">tylervigen.com</a>, shows a correlation of close to 95% for cheese consumption and number of people who died by becoming tangled in their bed sheets:</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508422161correlation.png\" alt=\"correlation between heese consumption and death my becoming entangled in bedsheets\" width=\"945\" height=\"469\" class=\"aligncenter size-full wp-image-160851\" /></p>\n<p>There’s also a strong correlation between ice cream sales and drownings at sea, as both go up in the summer. Only an analyst severely lacking common sense would say that ice cream causes drowning, though!</p>\n<p>The correlation versus causation issue is probably the most prolific mistake I see people make when analyzing data. When it comes to website analytics, one example of this might be where data shows that people who use site search covert 50% more than those who don’t. This could convince UXers to encourage more people to use the site search. However, the more likely correlation is that people who use the site search are a more engaged audience than the average users, and also have a better idea of what they’re looking for—meaning that they naturally have higher conversion rates.</p>\n<p>Combining quant and qual (and sometimes your own common sense) will help ensure you don’t fall into the trap of confusing correlation and causation. Split testing is also a great way to determine true causation, and will help to protect against drawing incorrect conclusions from your data. We’ll cover split testing more in Chapter 6.</p>\n<h3 id=\"grouping-all-visits-together\">Grouping All Visits Together</h3>\n<p>As UXers, we know that different people use websites in different ways. We also know that the same person is likely to use a website differently when using different devices, or even using the same website at different times of the day. We need to include these considerations of user behavior in our quantitative analysis.</p>\n","protected":false},"author":72443,"featured_media":160977,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[6131,425,7429,412],"tags":[904,1287,1097],"_links":{"self":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/posts/160848"}],"collection":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/posts"}],"about":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/types/post"}],"author":[{"embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/users/72443"}],"replies":[{"embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/comments?post=160848"}],"version-history":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/posts/160848/revisions"}],"wp_featuredmedia":[{"embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/media/160977"}],"wp_attachment":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/media?parent=160848"}],"wp_term":[{"taxonomy":"category","embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/categories?post=160848"},{"taxonomy":"post_tag","embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/tags?post=160848"}],"curies":[{"name":"wp","href":"https://api.w.org/{rel}","templated":true}]}}
{"index":{"_index":"blogs","_id":160824,"_type":"default"}}
{"id":160824,"date":"2017-10-23T09:00:46","date_gmt":"2017-10-23T16:00:46","guid":{"rendered":"https://www.sitepoint.com/?p=160824"},"modified":"2017-10-22T23:24:05","modified_gmt":"2017-10-23T06:24:05","slug":"understanding-the-key-terms-in-analytics","status":"publish","type":"post","link":"https://www.sitepoint.com/understanding-the-key-terms-in-analytics/","title":{"rendered":"Your Guide to Understanding Key Analytics Terms"},"content":{"rendered":"<p><em>The following is a short extract from our book, <a href=\"https://www.sitepoint.com/premium/books/researching-ux-analytics\">Researching UX: Analytics</a>, written by Luke Hay. It’s the ultimate guide to using analytics for improved user experience. SitePoint Premium members get access with their membership, or you can buy a copy in stores worldwide.</em></p>\n<p>For those not used to looking at website analytics, some of the terminology can seem like a foreign language. This can get even more confusing when terms change, or when different tools use different terms to describe the same thing.</p>\n<p>Some analytics terms that are used regularly are often misunderstood. In some cases, a partial understanding of a term may be more dangerous than having no understanding at all. One commonly misunderstood example is the word “hit”.</p>\n<p>A <strong>hit</strong> is often thought of as being a synonym for a page view or a visit. This is not the case, as each file request to a web server is an individual hit.</p>\n<p>This means that, if a web page contains five images, a user viewing this page will count as one page view <em>but six hits</em> (the five images plus the HTML page itself). You can see how this misunderstanding can lead to a wildly inaccurate understanding of the data! This section covers the most important analytics terms. (There are also short definitions of the main terms in the glossary at the end of this book.)</p>\n<h3 id=\"dimensions-and-metrics\">Dimensions and Metrics</h3>\n<p>All the data in your analytics reports can be divided into dimensions and metrics. It’s important to know what each term means so that you can better analyze your data. A good understanding of dimensions and metrics is also important for setting up custom reports and dashboards.</p>\n<p><strong>Dimensions</strong> are a way to group data—a form of categorization or identification. A dimension does <em>not</em> refer to the <em>size</em> of something (a common misunderstanding). Dimensions are normally shown in the first column of your reports. Examples of dimensions include <em>Country</em>, <em>Page Title</em> and <em>Device Type</em>.</p>\n<p><strong>Metrics</strong>, on the other hand, are the numbers associated with those dimensions. They appear in the other columns of your reports, showing the numbers relating to the dimensions in the first column. Examples of metrics include <em>Pageviews</em>, <em>Bounce Rate</em> and <em>Avg. Time on Page</em>. Metrics help you understand the behavior of your users. They count how often things happen—such as the number of visits to your website or app. Metrics can be totals, averages or percentages of a total.</p>\n<p>The screenshot below shows dimensions and metrics, as well as the different ways metrics are counted:</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508343729dimensionsandmetrics.png\" alt=\"\" width=\"600\" height=\"195\" class=\"aligncenter size-full wp-image-160827\" /></p>\n<p>An easy way to differentiate the two is to remember that dimensions are often words, while metrics are more likely to be numbers.</p>\n<h3 id=\"sessions-visits-page-views-and-unique-page-views\">Sessions, Visits, Page Views and Unique Page Views</h3>\n<p>As touched on in the previous chapter, there is often confusion between sessions, visits and page views. Firstly, it’s worth pointing out that sessions and visits are essentially the same thing. Google Analytics previously used the term “visit”, but changed the terminology to “sessions” in 2014. Other tools, such as Adobe Analytics, still use the term “visits”.</p>\n<p>You’ll generally find that the two terms are used interchangeably, but as long as you know these are referring to the same thing, it shouldn’t be a problem.</p>\n<p>A <strong>session</strong>, or visit, is a group of interactions (or a single interaction) that a user takes within a given time frame on your website. Google Analytics sessions time out after 30 minutes of inactivity by default, though you can change this yourself in your analytics settings.</p>\n<p>This means that, if your user goes to make themself a coffee, leaving your website open in their browser, and returns within half an hour, this will be counted as the same session. The same can be said for users who hop between multiple tabs. More often than not, though, sessions represent continuous browsing of your website.</p>\n<p>Sessions don’t differentiate between unique individuals. They only count the number of sessions, regardless of who’s doing them. If I visit your website in the morning and come back in the evening, that would still count as two sessions. Using other metrics like <em>users</em> or <em>visitors</em> will give you information on about individuals who visit your website. The next section in this chapter covers users and visitors in detail.</p>\n<p><strong>Page views</strong> are simply views to an HTML page or, less commonly, virtual page views. A <strong>virtual page view</strong> is a way of telling Google Analytics to register a page view if a new HTML page has not been loaded. Virtual page views require additional tagging in the form of JavaScript code. You can use them everywhere where content is loaded without a reload of the page, or when two or more pieces of content can reside on the same URL—for example, a form submission, or one-page checkouts.</p>\n<p>You can have multiple page views during one session if a user is browsing your website. Page views are normally categorized as page views and unique page views. If a user views the same page more than once during a session, this will only count as a single unique page view. This is useful if you want to get an idea of how many sessions included a view to a particular page, but you don’t want that number inflated by users who returned to that page in the same session.</p>\n<h3 id=\"users-and-visitors\">Users and Visitors</h3>\n<p>As Uxers, we have a good idea of what a “user” is. In our industry, users would generally be defined as individual humans who interact with our product—often a website, app or a piece of software. Analytics packages rarely have a way of accurately identifying individuals, though, so in analytics the term “user” has a slightly different meaning from the normal one.</p>\n<p>Most of the major analytics tools will identify users based on cookies. If I visit your website from my laptop, your analytics tool will normally drop a cookie into my browser so that, when I return, it will recognize me as the same individual who visited previously.</p>\n<p>This is broadly correct, but it doesn’t take into account that I might share my laptop with someone else. This means that two different individuals can be counted as the same user. Conversely, analytics tools are often unable to identify cross-device (or cross-browser) visits. If I visit your website from my tablet, your analytics tool will be unlikely to identify me as the same user who visited from my laptop.</p>\n<p>If you have a website that requires users to log in, or uses some other sort of unique identifier such as an email address or mobile number, then this may enable you to track users across devices. This requires additional setup, though, and relies on users logging in or otherwise identifying themselves on each of their devices.</p>\n<p>As with sessions and visits, “users” and “visitors” are generally different terms for the same thing. Different tools will use different terminology, but as long as you remember that <em>visitors</em> and <em>users</em> both normally describe a theoretical individual, based on a cookie, then that’ll be good enough.</p>\n<p>Users, or visitors, are often broken down into “new” and “returning”. New visitors are people who have visited your website for the first time during your reporting period, while returning visitors have visited more than once. By breaking this down, your analytics tool enables you to easily compare the behavior of these two user groups.</p>\n<p>You need to be careful here, though, as the metrics “new” and “returning” may not be as accurate as you’d expect. As touched on previously, analytics packages rarely track cross-device visits. This means that, if I start something on my phone and finish it on my laptop, it’s likely that I’ll be recorded as a “new” user when I visit via my laptop. Also, users will be recorded as “new” if they clear their cookies, or have a JavaScript or ad blocker installed.</p>\n<h3 id=\"visit-session-duration-and-time-on-page\">Visit/Session Duration and Time on Page</h3>\n<p>Time-based metrics are notoriously inaccurate. This is partly due to the way they’re calculated, and partly due to the inability to track a user’s attention.</p>\n<p>Google Analytics calculates <strong>session duration</strong> as the time between the first and last interaction during a visit to your website. It does not, as you might expect, calculate the duration based on when the user arrives on your website and when they leave. Google Analytics has no way of knowing when a user exits your website; it can only track their interactions while they’re on it. This means that, if a user spends five minutes looking at your home page, 20 minutes reading a blog post, and then exits the website, their visit duration was just five minutes. Conversely, if a user has left your website open in another tab for ten minutes while they browse another site, as long as they return to your site and move on to another web page, that ten minutes will count towards their duration on your site!</p>\n<p><strong>Time-on-page</strong> metrics work in a similar fashion to session duration. The timer starts when a user first loads a particular page and stops when they move on to another page on the website. No time is recorded for that page if a user exits your website from there. This means that a user can read a long blog post on your website, but if they exit from that point before viewing any other pages, their recorded “time on page” will be zero seconds. If a user only visits a single page during their session, both their time on that page and their session duration will be registered as zero seconds.</p>\n<p>All of this means that time-based metrics are not very accurate at all.</p>\n<p>This underlines the importance of analyzing based on trends over time, rather than looking at exact figures. If your average session duration is five minutes, that may not tell you very much. You’re better off focusing on what the session duration was last month, or last year, and analyzing whether this has gone up or down—and, most importantly, finding out why.</p>\n<p>You need to be careful here, though. If, for example, a blog post on your website gets lots of attention on social media one month, and drives lots of users who just read the post, then leave, this alone could massively impact your average session duration. This underlines the need to be aware of what’s happening across all of your website, and to avoid focusing on the headline figures.</p>\n<h3 id=\"bounce-and-exit-rates\">Bounce and Exit Rates</h3>\n<p>Two metrics that often get confused are bounce and exit rates. These are reported in slightly different ways in different analytics tools. The definitions below are based on how they’re reported in Google Analytics.</p>\n<p>A <strong>bounce</strong> describes a single page visit to a website. This means that the user arrives on a page and then leaves without viewing any other pages. The bounce rate is the percentage of visits to a website, or web page, that were bounces. A bounce rate of 10% means that one in ten of your website visitors only visited one page during their session. It’s the same for individual pages. If your “about” page has a bounce rate of 50%, this means 50% of the sessions that included a visit to this page were single page visits.</p>\n<p>The <strong>exit rate</strong> for a page shows the percentage of visits to the page that ended with users exiting the site from there. The diagram below shows how bounces and exits differ.</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508343758bounceandexit.png\" alt=\"\" width=\"380\" height=\"247\" class=\"aligncenter size-full wp-image-160828\" /></p>\n<p>These two metrics are similar, but it’s important to understand the difference between them. The bounce rate for a page is largely affected by the number of people who enter the website on that page. Often exit rate is a more useful metric to use for this reason.</p>\n<p>It’s worth mentioning that a high bounce or exit rate isn’t always a bad thing. Users may land on a page, get the information they were looking for, and then leave happy. An example of this could be a user landing on the contact page of your website, finding your phone number and calling you. In this case, the user has achieved their objective quickly and efficiently.</p>\n<p>We’ll cover how best to use bounce and exit rates in your analysis later on. For now, though, just make sure you know the difference between the two.</p>\n<h3 id=\"conversions-and-goals\">Conversions and Goals</h3>\n<p>As described in the previous chapter, a <strong>goal</strong> is a notable action taken by a user on your website, or an action that’s taken off-site, but fed into your analytics tool. An example of this could be a phone call, if you have call tracking software running on your website.</p>\n<p>A goal could be as simple as viewing a particular page, or completing a particular form. Goals are often referred to as “conversions”, but they’re actually just one type of conversion. In Google Analytics, conversions also refer to purchases on ecommerce websites.</p>\n<p>People often talk about a website’s <strong>conversion rate</strong>. In Google Analytics, this is the percentage of visits that include a conversion—a user either triggering a goal or completing an ecommerce transaction. In other tools it may also refer to the percentage of unique users who have completed a conversion.</p>\n<p>If the website in question is an ecommerce site, the term conversion will normally just refer to purchases. If the website isn’t an ecommerce site, the conversion rate can either be a combined rate for all goals, or the conversion rate of the most important or primary goal.</p>\n<p>As there’s no consistent definition of what activity the conversion rate refers to, it’s always good to check what someone means when they use the term.</p>\n<p>A conversion is simply moving someone from one state to another. For example, moving someone who hasn’t made a purchase to someone who has. Or even moving someone who doesn’t like your brand to someone who does. Each desired conversion should be measurable in one way or another, and a goal or series of goals can be used to do this in analytics.</p>\n<h3 id=\"segments-and-filters\">Segments and Filters</h3>\n<p>Analytics tools will generally provide options for segmenting or filtering your data. <strong>Segmentation</strong> describes grouping users with similar characteristics and viewing the data for those groups, often in comparison with other groups. An example would be segmenting your users by the device they used to visit your website—that is, by mobile, tablet or desktop. <strong>Filtering</strong> has a similar purpose, but it removes data from a certain group, or groups, leaving you with only the data from the group(s) that you want to collect.</p>\n<p>In Google Analytics, filters and segments are separate options, but are often confused with each other.</p>\n<p>Filters are applied at the view level of an account, and filter out information from ever being recorded in your reports. For example, if you filter out visits from your IP address for a view, that data simply won’t be collected for that view. Filters are useful for excluding data that may otherwise skew your reports in ways you don’t want.</p>\n<p>Segments are applied at report level, and temporarily filter out information from all reports. For example, you might want to create a segment for mobile users from France. Once this segment is applied, all of your reports will only include data for French mobile users. The segment will stop being applied either when you manually remove it, or when you close Google Analytics and return. Segments can be really useful for analyzing the behavior of different user groups. We’ll cover segmenting data in more detail later in this chapter.</p>\n","protected":false},"excerpt":{"rendered":"<p><em>The following is a short extract from our book, <a href=\"https://www.sitepoint.com/premium/books/researching-ux-analytics\">Researching UX: Analytics</a>, written by Luke Hay. It’s the ultimate guide to using analytics for improved user experience. SitePoint Premium members get access with their membership, or you can buy a copy in stores worldwide.</em></p>\n<p>For those not used to looking at website analytics, some of the terminology can seem like a foreign language. This can get even more confusing when terms change, or when different tools use different terms to describe the same thing.</p>\n<p>Some analytics terms that are used regularly are often misunderstood. In some cases, a partial understanding of a term may be more dangerous than having no understanding at all. One commonly misunderstood example is the word “hit”.</p>\n<p>A <strong>hit</strong> is often thought of as being a synonym for a page view or a visit. This is not the case, as each file request to a web server is an individual hit.</p>\n<p>This means that, if a web page contains five images, a user viewing this page will count as one page view <em>but six hits</em> (the five images plus the HTML page itself). You can see how this misunderstanding can lead to a wildly inaccurate understanding of the data! This section covers the most important analytics terms. (There are also short definitions of the main terms in the glossary at the end of this book.)</p>\n<h3 id=\"dimensions-and-metrics\">Dimensions and Metrics</h3>\n<p>All the data in your analytics reports can be divided into dimensions and metrics. It’s important to know what each term means so that you can better analyze your data. A good understanding of dimensions and metrics is also important for setting up custom reports and dashboards.</p>\n<p><strong>Dimensions</strong> are a way to group data—a form of categorization or identification. A dimension does <em>not</em> refer to the <em>size</em> of something (a common misunderstanding). Dimensions are normally shown in the first column of your reports. Examples of dimensions include <em>Country</em>, <em>Page Title</em> and <em>Device Type</em>.</p>\n<p><strong>Metrics</strong>, on the other hand, are the numbers associated with those dimensions. They appear in the other columns of your reports, showing the numbers relating to the dimensions in the first column. Examples of metrics include <em>Pageviews</em>, <em>Bounce Rate</em> and <em>Avg. Time on Page</em>. Metrics help you understand the behavior of your users. They count how often things happen—such as the number of visits to your website or app. Metrics can be totals, averages or percentages of a total.</p>\n<p>The screenshot below shows dimensions and metrics, as well as the different ways metrics are counted:</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508343729dimensionsandmetrics.png\" alt=\"\" width=\"600\" height=\"195\" class=\"aligncenter size-full wp-image-160827\" /></p>\n<p>An easy way to differentiate the two is to remember that dimensions are often words, while metrics are more likely to be numbers.</p>\n<h3 id=\"sessions-visits-page-views-and-unique-page-views\">Sessions, Visits, Page Views and Unique Page Views</h3>\n<p>As touched on in the previous chapter, there is often confusion between sessions, visits and page views. Firstly, it’s worth pointing out that sessions and visits are essentially the same thing. Google Analytics previously used the term “visit”, but changed the terminology to “sessions” in 2014. Other tools, such as Adobe Analytics, still use the term “visits”.</p>\n<p>You’ll generally find that the two terms are used interchangeably, but as long as you know these are referring to the same thing, it shouldn’t be a problem.</p>\n<p>A <strong>session</strong>, or visit, is a group of interactions (or a single interaction) that a user takes within a given time frame on your website. Google Analytics sessions time out after 30 minutes of inactivity by default, though you can change this yourself in your analytics settings.</p>\n<p>This means that, if your user goes to make themself a coffee, leaving your website open in their browser, and returns within half an hour, this will be counted as the same session. The same can be said for users who hop between multiple tabs. More often than not, though, sessions represent continuous browsing of your website.</p>\n<p>Sessions don’t differentiate between unique individuals. They only count the number of sessions, regardless of who’s doing them. If I visit your website in the morning and come back in the evening, that would still count as two sessions. Using other metrics like <em>users</em> or <em>visitors</em> will give you information on about individuals who visit your website. The next section in this chapter covers users and visitors in detail.</p>\n<p><strong>Page views</strong> are simply views to an HTML page or, less commonly, virtual page views. A <strong>virtual page view</strong> is a way of telling Google Analytics to register a page view if a new HTML page has not been loaded. Virtual page views require additional tagging in the form of JavaScript code. You can use them everywhere where content is loaded without a reload of the page, or when two or more pieces of content can reside on the same URL—for example, a form submission, or one-page checkouts.</p>\n<p>You can have multiple page views during one session if a user is browsing your website. Page views are normally categorized as page views and unique page views. If a user views the same page more than once during a session, this will only count as a single unique page view. This is useful if you want to get an idea of how many sessions included a view to a particular page, but you don’t want that number inflated by users who returned to that page in the same session.</p>\n<h3 id=\"users-and-visitors\">Users and Visitors</h3>\n<p>As Uxers, we have a good idea of what a “user” is. In our industry, users would generally be defined as individual humans who interact with our product—often a website, app or a piece of software. Analytics packages rarely have a way of accurately identifying individuals, though, so in analytics the term “user” has a slightly different meaning from the normal one.</p>\n<p>Most of the major analytics tools will identify users based on cookies. If I visit your website from my laptop, your analytics tool will normally drop a cookie into my browser so that, when I return, it will recognize me as the same individual who visited previously.</p>\n<p>This is broadly correct, but it doesn’t take into account that I might share my laptop with someone else. This means that two different individuals can be counted as the same user. Conversely, analytics tools are often unable to identify cross-device (or cross-browser) visits. If I visit your website from my tablet, your analytics tool will be unlikely to identify me as the same user who visited from my laptop.</p>\n<p>If you have a website that requires users to log in, or uses some other sort of unique identifier such as an email address or mobile number, then this may enable you to track users across devices. This requires additional setup, though, and relies on users logging in or otherwise identifying themselves on each of their devices.</p>\n<p>As with sessions and visits, “users” and “visitors” are generally different terms for the same thing. Different tools will use different terminology, but as long as you remember that <em>visitors</em> and <em>users</em> both normally describe a theoretical individual, based on a cookie, then that’ll be good enough.</p>\n<p>Users, or visitors, are often broken down into “new” and “returning”. New visitors are people who have visited your website for the first time during your reporting period, while returning visitors have visited more than once. By breaking this down, your analytics tool enables you to easily compare the behavior of these two user groups.</p>\n<p>You need to be careful here, though, as the metrics “new” and “returning” may not be as accurate as you’d expect. As touched on previously, analytics packages rarely track cross-device visits. This means that, if I start something on my phone and finish it on my laptop, it’s likely that I’ll be recorded as a “new” user when I visit via my laptop. Also, users will be recorded as “new” if they clear their cookies, or have a JavaScript or ad blocker installed.</p>\n<h3 id=\"visit-session-duration-and-time-on-page\">Visit/Session Duration and Time on Page</h3>\n<p>Time-based metrics are notoriously inaccurate. This is partly due to the way they’re calculated, and partly due to the inability to track a user’s attention.</p>\n<p>Google Analytics calculates <strong>session duration</strong> as the time between the first and last interaction during a visit to your website. It does not, as you might expect, calculate the duration based on when the user arrives on your website and when they leave. Google Analytics has no way of knowing when a user exits your website; it can only track their interactions while they’re on it. This means that, if a user spends five minutes looking at your home page, 20 minutes reading a blog post, and then exits the website, their visit duration was just five minutes. Conversely, if a user has left your website open in another tab for ten minutes while they browse another site, as long as they return to your site and move on to another web page, that ten minutes will count towards their duration on your site!</p>\n<p><strong>Time-on-page</strong> metrics work in a similar fashion to session duration. The timer starts when a user first loads a particular page and stops when they move on to another page on the website. No time is recorded for that page if a user exits your website from there. This means that a user can read a long blog post on your website, but if they exit from that point before viewing any other pages, their recorded “time on page” will be zero seconds. If a user only visits a single page during their session, both their time on that page and their session duration will be registered as zero seconds.</p>\n<p>All of this means that time-based metrics are not very accurate at all.</p>\n<p>This underlines the importance of analyzing based on trends over time, rather than looking at exact figures. If your average session duration is five minutes, that may not tell you very much. You’re better off focusing on what the session duration was last month, or last year, and analyzing whether this has gone up or down—and, most importantly, finding out why.</p>\n<p>You need to be careful here, though. If, for example, a blog post on your website gets lots of attention on social media one month, and drives lots of users who just read the post, then leave, this alone could massively impact your average session duration. This underlines the need to be aware of what’s happening across all of your website, and to avoid focusing on the headline figures.</p>\n<h3 id=\"bounce-and-exit-rates\">Bounce and Exit Rates</h3>\n<p>Two metrics that often get confused are bounce and exit rates. These are reported in slightly different ways in different analytics tools. The definitions below are based on how they’re reported in Google Analytics.</p>\n<p>A <strong>bounce</strong> describes a single page visit to a website. This means that the user arrives on a page and then leaves without viewing any other pages. The bounce rate is the percentage of visits to a website, or web page, that were bounces. A bounce rate of 10% means that one in ten of your website visitors only visited one page during their session. It’s the same for individual pages. If your “about” page has a bounce rate of 50%, this means 50% of the sessions that included a visit to this page were single page visits.</p>\n<p>The <strong>exit rate</strong> for a page shows the percentage of visits to the page that ended with users exiting the site from there. The diagram below shows how bounces and exits differ.</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508343758bounceandexit.png\" alt=\"\" width=\"380\" height=\"247\" class=\"aligncenter size-full wp-image-160828\" /></p>\n<p>These two metrics are similar, but it’s important to understand the difference between them. The bounce rate for a page is largely affected by the number of people who enter the website on that page. Often exit rate is a more useful metric to use for this reason.</p>\n","protected":false},"author":72443,"featured_media":160972,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[6131,425,412],"tags":[904,1097],"_links":{"self":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/posts/160824"}],"collection":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/posts"}],"about":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/types/post"}],"author":[{"embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/users/72443"}],"replies":[{"embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/comments?post=160824"}],"version-history":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/posts/160824/revisions"}],"wp_featuredmedia":[{"embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/media/160972"}],"wp_attachment":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/media?parent=160824"}],"wp_term":[{"taxonomy":"category","embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/categories?post=160824"},{"taxonomy":"post_tag","embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/tags?post=160824"}],"curies":[{"name":"wp","href":"https://api.w.org/{rel}","templated":true}]}}
{"index":{"_index":"blogs","_id":160796,"_type":"default"}}
{"id":160796,"date":"2017-10-20T09:00:24","date_gmt":"2017-10-20T16:00:24","guid":{"rendered":"https://www.sitepoint.com/?p=160796"},"modified":"2017-10-19T23:43:47","modified_gmt":"2017-10-20T06:43:47","slug":"using-adobe-xds-smart-guides","status":"publish","type":"post","link":"https://www.sitepoint.com/using-adobe-xds-smart-guides/","title":{"rendered":"How to Use Adobe XD’s Smart Guides"},"content":{"rendered":"<p><em>The following is a short extract from our book, <a href=\"https://www.sitepoint.com/premium/books/jump-start-adobe-xd\">Jump Start Adobe XD</a>, written by Daniel Schwarz, a highly practical tutorial on this fantastic prototyping tool. SitePoint Premium members get access with their membership, or you can buy a copy in stores worldwide.</em></p>\n<p>Smart Guides were originally introduced in Sketch and later adopted in Photoshop after the feature became a hit. Adobe XD explains them in their help section: <em>“When you move an object or artboard, use Smart Guides to align the selected object or artboard to other objects or artboards. The alignment is based on the geometry of objects and artboards. Guides appear as the object approaches the edge or center point of other objects."</em></p>\n<p>Let me start by saying than an object is a common term used to describe a shape layer, text layer, group or bitmap on the canvas. Basically, any type of layer or group is an object.</p>\n<p>Guides are visual cues that illustrate how objects align to one another — they can display the distance between two layers, or indicate whether or not a layer has snapped to the bounds of another object or artboard edge. Adobe XD will try to anticipate where you want to move a layer, and automatically snap to that location when you draw close to it, while showing how far you have left until you reach it. You can work out the distance manually by selecting the first layer, holding <strong>Option/Alt</strong>, and hovering over the <em>second</em> layer.</p>\n<h3 id=\"manual-alignments\">Manual Alignments</h3>\n<p>Let's start by aligning a layer manually, so we understand the difference. A moment ago we grouped two text layers together — select both of them once more (hold <strong>Shift</strong> while you click them) and click the <em>Align Center (Horizontally)</em> button in the Inspector, or use the shortcut: <strong>Cmd + Control + C</strong> (<strong>Shift + C</strong> in Windows).</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508342238center-align.png\" alt=\"\" width=\"901\" height=\"695\" class=\"aligncenter size-full wp-image-160808\" /></p>\n<h3 id=\"smart-guides-when-moving-layers\">Smart Guides When Moving Layers</h3>\n<p>Now select the <em>actual</em> group. You can either use the <em>Select</em> tool (keyboard shortcut: <strong>V</strong>) and select the group by clicking on it, or use the <strong>Esc</strong> key to traverse up to the <em>parent</em> container, which is the group. Move it until two things happen:</p>\n<ol>\n<li>It appears 28px below the form</li>\n<li>It snaps to the dead-center of the artboard horizontally</li>\n</ol>\n<p>You’ll know you’ve done this correctly because the colored lines of the smart guides will illustrate what the object has snapped to (which will be the dead-center of the artboard, as indicated by the vertical line that appears). You'll also notice the relative distance between the search function group and the welcome text group (as indicated by the numerical value). </p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508342267smart-move.png\" alt=\"\" width=\"890\" height=\"576\" class=\"aligncenter size-full wp-image-160809\" /></p>\n<h3 id=\"smart-guides-with-option-alt-hold\">Smart Guides With Option/Alt-Hold</h3>\n<p>Select the bottom-most layer of this group, hold <strong>Option</strong> (<strong>Alt</strong> in Windows), then hover the cursor over the top-most layer. This is a manual approach (also known as <strong>Option/Alt-hold</strong>) to measuring the relative distance between two layers. You can move layers as normal while option-holding, so use the <strong>↑→↓←</strong> arrow keys until the distance is 5px.</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508342291smart-opt.png\" alt=\"\" width=\"890\" height=\"547\" class=\"aligncenter size-full wp-image-160810\" /></p>\n<p>Let's use what we've learned to add some more elements. So far we’ve taken our first look at shape layers, text layers, grouping of layers, alignments, smart guides, and some other basics. Let's recap some of that and finish off this screen, starting with a bottom navigation component with four links.</p>\n<p>Create a rectangle that’s 345 x 44px (44px, width <em>and</em> height, is the minimum size for a tap target — tap targets smaller than this are very hard for the user to tap). Use <strong>Option/Alt-Hold</strong> to ensure that the rectangle has a 15px margin on three sides.</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508342789smart-15.png\" alt=\"\" width=\"901\" height=\"638\" class=\"aligncenter size-full wp-image-160813\" /></p>\n<p>Now we have the basic shape of the navbar component.</p>\n<p>Draw another rectangle where the width is 25% of the navbar’s total width (because we’ll need to create four links inside the navbar, where each link is 25% of the total width). Start your draw from the top-left corner of the navbar’s rectangle. You’ll see the smart guides again, indicating that your draw will snap from the corner of that layer, which is what we want.</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508342813smart-draw.png\" alt=\"\" width=\"890\" height=\"583\" class=\"aligncenter size-full wp-image-160814\" /></p>\n<p>With the Ellipse (<strong>E</strong>) tool, draw a 14 x 14px circle (hold <strong>Shift</strong> to maintain aspect ratio) and group together the navbar link and circle, which substitutes for a navbar icon for the time being. Duplicate this group three times and drag each one horizontally to distribute them evenly inside the navbar.</p>\n<p>Finally, <strong>group the entire component</strong>.</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508342832navbar.png\" alt=\"\" width=\"890\" height=\"602\" class=\"aligncenter size-full wp-image-160815\" /></p>\n<h3 id=\"renaming-layers\">Renaming Layers</h3>\n<p>We now have a lo-fi mockup of the navbar, but we also have a lot of objects that are named “rectangle” and “group”, which is confusing if you’re trying to locate a layer within the layer list.</p>\n<p>At this moment in time there’s no shortcut for renaming layers, so you’ll have to double-click on the layer’s name in the layer list, and rename it by typing in a new name for the layer. Renaming layers helps you maintain cleanliness in your design, and makes the layer list look a lot less confusing.</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508342854rename.png\" alt=\"\" width=\"906\" height=\"768\" class=\"aligncenter size-full wp-image-160816\" /></p>\n<p>Wrap up this screen by creating three more layers:</p>\n<ol>\n<li>A rectangle, renamed to “Logo BG”</li>\n<li>A text layer called “DISHY”</li>\n<li>A group to contain these two layers, renamed to “Logo”</li>\n</ol>\n<p>Centralise the group horizontally/vertically in the top space.</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508342872screen-wrap.png\" alt=\"\" width=\"914\" height=\"665\" class=\"aligncenter size-full wp-image-160817\" /></p>\n<h2 id=\"fast-forward\">Fast-Forward</h2>\n<p>Fast-forward 30 minutes and we have an additional screen. When the user has searched for a type of cuisine using the form on the welcome screen, they’re then invited to set their location so the app can return results relevant to the user's location.</p>\n<p>In the next chapter we’ll prototype/demonstrate this user flow, but for now let's finish mocking up this screen while learning about Adobe XD’s <em>other</em> design tools. From the archive, grab the support file named <a href=\"https://github.com/spbooks/jsadobexd1/blob/master/C2.xd\">C2.xd</a> to continue.</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508342894next-screen.png\" alt=\"\" width=\"1366\" height=\"768\" class=\"aligncenter size-full wp-image-160818\" /></p>\n<h2 id=\"repeat-grids\">Repeat Grids</h2>\n<p>Repeat grids allow you to repeat objects horizontally and/or vertically — it’s a much quicker way of duplicating and distributing objects so you won’t have to duplicate and position them manually. Select the “Recent Locations” group from the “Set Location” artboard I’ve added into the support file, and hit the “Repeat Grid” button in the inspector, or use the keyboard shortcut <strong>Cmd + R</strong> (<strong>Ctrl + R</strong> in Windows).</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508342911make-repeat.png\" alt=\"\" width=\"809\" height=\"597\" class=\"aligncenter size-full wp-image-160819\" /></p>\n<p>You’ll notice that this component now has two tuggable handles. Pull the right one to repeat the component horizontally, and the bottom one to repeat it vertically. In this case, we want to repeat it vertically, so move forward and do that. Note that it doesn’t matter if the content overflows the artboard; in fact, in the next chapter we’ll learn all about scrollable prototypes.</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508342928repeating.png\" alt=\"\" width=\"924\" height=\"677\" class=\"aligncenter size-full wp-image-160820\" /></p>\n<p>If you use the cursor to hover over the space in between the repeated objects, you’ll be able to click and drag that space to adjust it. Adjust the spacing to 20px (you’ll notice the spacing adjustment applies to all repeated objects).</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508342944repeat-space.png\" alt=\"\" width=\"861\" height=\"559\" class=\"aligncenter size-full wp-image-160821\" /> </p>\n<h2 id=\"next-prototyping-user-flows-and-receiving-feedback\">Next: Prototyping User Flows and Receiving Feedback</h2>\n<p>In the next chapter we’ll take a look at the prototyping workspace, where we’ll learn how to create user flows and interactions. We’ll also learn how to share prototypes, accept comments on them, and even record user flows so we can make video demonstrations of how the prototype works.</p>\n","protected":false},"excerpt":{"rendered":"<p><em>The following is a short extract from our book, <a href=\"https://www.sitepoint.com/premium/books/jump-start-adobe-xd\">Jump Start Adobe XD</a>, written by Daniel Schwarz, a highly practical tutorial on this fantastic prototyping tool. SitePoint Premium members get access with their membership, or you can buy a copy in stores worldwide.</em></p>\n<p>Smart Guides were originally introduced in Sketch and later adopted in Photoshop after the feature became a hit. Adobe XD explains them in their help section: <em>“When you move an object or artboard, use Smart Guides to align the selected object or artboard to other objects or artboards. The alignment is based on the geometry of objects and artboards. Guides appear as the object approaches the edge or center point of other objects."</em></p>\n<p>Let me start by saying than an object is a common term used to describe a shape layer, text layer, group or bitmap on the canvas. Basically, any type of layer or group is an object.</p>\n<p>Guides are visual cues that illustrate how objects align to one another — they can display the distance between two layers, or indicate whether or not a layer has snapped to the bounds of another object or artboard edge. Adobe XD will try to anticipate where you want to move a layer, and automatically snap to that location when you draw close to it, while showing how far you have left until you reach it. You can work out the distance manually by selecting the first layer, holding <strong>Option/Alt</strong>, and hovering over the <em>second</em> layer.</p>\n<h3 id=\"manual-alignments\">Manual Alignments</h3>\n<p>Let's start by aligning a layer manually, so we understand the difference. A moment ago we grouped two text layers together — select both of them once more (hold <strong>Shift</strong> while you click them) and click the <em>Align Center (Horizontally)</em> button in the Inspector, or use the shortcut: <strong>Cmd + Control + C</strong> (<strong>Shift + C</strong> in Windows).</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508342238center-align.png\" alt=\"\" width=\"901\" height=\"695\" class=\"aligncenter size-full wp-image-160808\" /></p>\n<h3 id=\"smart-guides-when-moving-layers\">Smart Guides When Moving Layers</h3>\n<p>Now select the <em>actual</em> group. You can either use the <em>Select</em> tool (keyboard shortcut: <strong>V</strong>) and select the group by clicking on it, or use the <strong>Esc</strong> key to traverse up to the <em>parent</em> container, which is the group. Move it until two things happen:</p>\n<ol>\n<li>It appears 28px below the form</li>\n<li>It snaps to the dead-center of the artboard horizontally</li>\n</ol>\n<p>You’ll know you’ve done this correctly because the colored lines of the smart guides will illustrate what the object has snapped to (which will be the dead-center of the artboard, as indicated by the vertical line that appears). You'll also notice the relative distance between the search function group and the welcome text group (as indicated by the numerical value). </p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508342267smart-move.png\" alt=\"\" width=\"890\" height=\"576\" class=\"aligncenter size-full wp-image-160809\" /></p>\n<h3 id=\"smart-guides-with-option-alt-hold\">Smart Guides With Option/Alt-Hold</h3>\n<p>Select the bottom-most layer of this group, hold <strong>Option</strong> (<strong>Alt</strong> in Windows), then hover the cursor over the top-most layer. This is a manual approach (also known as <strong>Option/Alt-hold</strong>) to measuring the relative distance between two layers. You can move layers as normal while option-holding, so use the <strong>↑→↓←</strong> arrow keys until the distance is 5px.</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508342291smart-opt.png\" alt=\"\" width=\"890\" height=\"547\" class=\"aligncenter size-full wp-image-160810\" /></p>\n<p>Let's use what we've learned to add some more elements. So far we’ve taken our first look at shape layers, text layers, grouping of layers, alignments, smart guides, and some other basics. Let's recap some of that and finish off this screen, starting with a bottom navigation component with four links.</p>\n","protected":false},"author":71978,"featured_media":160891,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[6131,8597,8760,8005,412,8601],"tags":[9927,816,8006,1097,10550,11582],"_links":{"self":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/posts/160796"}],"collection":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/posts"}],"about":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/types/post"}],"author":[{"embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/users/71978"}],"replies":[{"embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/comments?post=160796"}],"version-history":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/posts/160796/revisions"}],"wp_featuredmedia":[{"embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/media/160891"}],"wp_attachment":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/media?parent=160796"}],"wp_term":[{"taxonomy":"category","embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/categories?post=160796"},{"taxonomy":"post_tag","embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/tags?post=160796"}],"curies":[{"name":"wp","href":"https://api.w.org/{rel}","templated":true}]}}
{"index":{"_index":"blogs","_id":160675,"_type":"default"}}
{"id":160675,"date":"2017-10-19T09:30:35","date_gmt":"2017-10-19T16:30:35","guid":{"rendered":"https://www.sitepoint.com/?p=160675"},"modified":"2017-10-18T16:24:33","modified_gmt":"2017-10-18T23:24:33","slug":"productivity-tips-for-webstorm-and-angular-part-1","status":"publish","type":"post","link":"https://www.sitepoint.com/productivity-tips-for-webstorm-and-angular-part-1/","title":{"rendered":"Top 12 Productivity Tips for WebStorm and Angular – Part 1"},"content":{"rendered":"<p class=\"wp-special\"><em>This article was sponsored by <a href=\"https://www.jetbrains.com/\" rel=\"nofollow\">JetBrains</a>. Thank you for supporting the partners who make SitePoint possible.</em></p>\n<p>In this 2-part series, Google Developer Experts <a href=\"https://twitter.com/jvandemo\">Jurgen Van de Moere</a> and <a href=\"https://twitter.com/toddmotto\">Todd Motto</a> share their favorite productivity tips for developing Angular applications using WebStorm.</p>\n<p>In this first part, Jurgen shares his personal top 5 <a href=\"https://www.jetbrains.com/webstorm/\">WebStorm</a> features that allow him to increase his productivity on a daily basis:</p>\n<ol>\n<li>Use <a href=\"https://cli.angular.io/\">Angular CLI</a> from within <a href=\"https://www.jetbrains.com/webstorm/\">WebStorm</a></li>\n<li>Navigate like a pro</li>\n<li>Take advantage of <a href=\"https://next.angular.io/guide/language-service\">Angular Language Service</a></li>\n<li>Auto format your code</li>\n<li>Optimize your imports</li>\n</ol>\n<p>Each tip can tremendously increase your development productivity, so let’s dig into them a little deeper one by one.</p>\n<h2 id=\"tip1useangularclifromwithinwebstorm\">Tip 1: Use Angular CLI from Within WebStorm</h2>\n<p><a href=\"https://cli.angular.io/\">Angular CLI</a> is a Command Line Interface (CLI), written and maintained by the Angular team, to help automate your development workflow. You can use it to quickly create new Angular projects and add new features such as components, services and directives to existing Angular projects.</p>\n<p>WebStorm’s integration with Angular CLI provides you with all its power right from within WebStorm, without using the terminal.</p>\n<p>To create a new Angular Project, choose <strong>File | New | Project</strong> and select <strong>Angular CLI</strong>.</p>\n<p>Enter a project location and hit the <strong>Create</strong> button. WebStorm uses Angular CLI to create a new Angular project and install dependencies.</p>\n<p>When your new Angular application is in place, you can easily add new Angular features. Right click on <code>src/app</code> and choose <strong>New | Angular CLI</strong> to pick the type of feature you wish to add.</p>\n<p>Once you’ve selected a feature, you can specify the name and optional parameters, just as you would with Angular CLI on the command line:</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/150813951101-generate-new-project.gif\" alt=\"Create a new Angular module\" width=\"1024\" height=\"576\" class=\"aligncenter size-large wp-image-160696\" /></p>\n<blockquote>\n<p>To learn more about Angular CLI options and parameters, make sure to check out <a href=\"https://www.sitepoint.com/ultimate-angular-cli-reference/\">The Ultimate Angular CLI Reference</a>.</p>\n</blockquote>\n<p>What’s really awesome is that WebStorm automatically adds the component to the right Angular module for you, in this case <code>AppModule</code>.</p>\n<p>If your application has multiple Angular modules, right click on the module you wish to add the feature to and choose <strong>New | Angular CLI</strong>. WebStorm will make sure the new files are created in the right location and that the new feature is added to the correct Angular module.</p>\n<p>How sweet is that!</p>\n<h2 id=\"tip2navigatelikeapro\">Tip 2: Navigate Like a Pro</h2>\n<p>Use <code>cmd-click</code> or <code>cmd-B</code> to easily jump to any definition within your project.</p>\n<p>If you are a keyboard user, just put your cursor on a term and hit <code>cmd-B</code>. If you are a mouse user, hold down the <code>cmd</code> button and all terms you hover will turn into links to their definition.</p>\n<p>WebStorm automatically recognizes Angular components and directives in your HTML, links to stylesheets, links to templates, classes, interfaces and much more.</p>\n<p>No need to open file(s) manually, just jump to any definition you need:</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/150813900202-cmd-click.gif\" alt=\"Command-click words\" width=\"1024\" height=\"576\" class=\"aligncenter size-large wp-image-160682\" /></p>\n<p>When looking for a file that you don’t have an immediate reference to, hit <code>shift</code> twice to open the <strong>Search everywhere</strong> dialog. You don’t have to type the entire search string. If you want to open <code>AppComponent</code>, just type the first letter of each part — i.e. <code>ac</code> — and WebStorm will immediately narrow down the result list for you, so you can quickly pick the suggestion you wish to open:</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/150813903302-search-everywhere-1024x614.png\" alt=\"Search everywhere\" width=\"1024\" height=\"614\" class=\"aligncenter size-large wp-image-160683\" /></p>\n<p>Another super useful navigation shortcut is <code>cmd-E</code>, which presents you with a list of recently edited files so you can easily navigate back and forth between them.</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/150813905402-recent-files-1024x606.png\" alt=\"Recent files\" width=\"1024\" height=\"606\" class=\"aligncenter size-large wp-image-160684\" /></p>\n<p>Knowing how to quickly navigate to the code you need will save you a tremendous amount of time every single day.</p>\n<h2 id=\"tip3takeadvantageofangularlanguageservice\">Tip 3: Take Advantage of Angular Language Service</h2>\n<p>By default, WebStorm already provides great assistance for writing Angular code.</p>\n<p>When editing a script, WebStorm automatically imports the required JavaScript modules so you don’t have to import them manually.</p>\n<p>If you open up the TypeScript panel, WebStorm provides you with immediate feedback on the validity of your code, so you can quickly resolve issues before having to compile your project.</p>\n<p>Watch how the <code>OnInit</code> interface is automatically imported and how the live TypeScript feedback immediately tells you whether or not your TypeScript code is valid: </p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/150813912103-language-services.gif\" alt=\"TypeScript recommendations\" width=\"1024\" height=\"576\" class=\"aligncenter size-large wp-image-160687\" /></p>\n<p>When you edit a template, WebStorm provides you with smart code completion that recognizes components, directives and even input and output properties:</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/150813915203-autocomplete-in-templates.gif\" alt=\"Code completion in templates\" width=\"1024\" height=\"576\" class=\"aligncenter size-large wp-image-160688\" /></p>\n<p>You can take things further by installing the <a href=\"https://next.angular.io/guide/language-service\">Angular Language Service</a>. This is a service, designed by the Angular Team, to provide IDEs with error checking and type completion within Angular templates.</p>\n<p>WebStorm integrates with Angular Language Service to better understand your code. To enable Angular Language Service, first make sure it is installed:</p>\n<pre><code class=\"bash language-bash\">npm install @angular/language-service --save-dev \r\n</code></pre>\n<blockquote>\n<p>If you use Angular CLI to generate an Angular application, Angular Language Service is automatically installed.</p>\n</blockquote>\n<p>Next, go to <strong>Preferences | Languages & Frameworks | TypeScript</strong>, make sure <strong>Use TypeScript Service</strong> is checked and click <strong>Configure…</strong>:</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/150813907803-configure-typescript-service-1024x710.png\" alt=\"TypeScript recommendations\" width=\"1024\" height=\"710\" class=\"aligncenter size-large wp-image-160685\" /></p>\n<p>The <strong>Service Options</strong> modal will pop up. Enable <strong>Use Angular service</strong> and apply the changes:</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/150813909603-enable-angular-service.png\" alt=\"TypeScript recommendations\" width=\"576\" height=\"464\" class=\"aligncenter size-full wp-image-160686\" /></p>\n<p>With Angular Language Service enabled, WebStorm is able to improve code completion in template expressions:</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/150813919003-template-expressions.gif\" alt=\"Angular Language Service Expression Error\" width=\"1024\" height=\"576\" class=\"aligncenter size-large wp-image-160689\" /></p>\n<p>… and report template errors more precisely right inside your editor:</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/150813921503-highlighted-errors-1024x612.png\" alt=\"Highlighted errors\" width=\"1024\" height=\"612\" class=\"aligncenter size-large wp-image-160690\" /></p>\n<p>Catching errors without having to compile your project saves you incredible amounts of time.</p>\n<h2 id=\"tip4autoformatyourcode\">Tip 4: Auto-format Your Code</h2>\n<p>Don’t worry about formatting your code manually. WebStorm has you covered.</p>\n<p>Whether your are in a template, a script, a stylesheet or even a JSON file, just hit <code>cmd-option-L</code> and WebStorm will automatically format all code for you:</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/150813924004-auto-format.gif\" alt=\"Auto-format\" width=\"1024\" height=\"576\" class=\"aligncenter size-large wp-image-160691\" /></p>\n<p>If your project has a <code>tslint.json</code> file, just open it up and WebStorm will ask you whether you want to apply the code style from TSLint to your project: </p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/150813927304-apply-code-style-1024x612.png\" alt=\"Import auto format options from TS Lint\" width=\"1024\" height=\"612\" class=\"aligncenter size-large wp-image-160692\" /></p>\n<p>If you are not happy with the style of the auto-formatted code, you can fine-tune the format settings for every supported language separately in <strong>Webstorm | Preferences | Editor | Code Style</strong>:</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/150813929204-configure-code-style-1024x613.png\" alt=\"Configure code style\" width=\"1024\" height=\"613\" class=\"aligncenter size-large wp-image-160693\" /></p>\n<p>WebStorm’s code formatting feature ensures that your code is formatted properly according to your project settings, so that your code linting checks pass successfully and you can focus on writing code.</p>\n<h2 id=\"tip5optimizeyourimports\">Tip 5: Optimize Your Imports</h2>\n<p>When working on an Angular script, you may find that certain imports are no longer used.</p>\n<p>If you don’t remove the unused imports, your bundle size may grow larger than needed. However, removing unused imports can be a real chore. Not with WebStorm!</p>\n<p>Hit <code>ctrl-alt-O</code> to optimize your imports instantly. Alternatively, you can hit <code>cmd-shift-A</code> to open up the <strong>Find actions</strong> panel, type <code>optim</code> to find the <strong>Optimize imports</strong> action and hit the <code>enter</code> key to run the action.</p>\n<p>When optimizing imports, WebStorm will do the following for you:</p>\n<ul>\n<li>merge imports from the same module in the same <code>import</code> statement</li>\n<li>remove unused imports</li>\n<li>reformat import statements so they fit within your desired line length</li>\n</ul>\n<p>In the following example, <strong>Optimize imports</strong> is run twice. The first time, it merges all imports from <code>@angular/core</code> into one import statement.</p>\n<p>Then the <code>OnInit</code>, <code>OnChanges</code> and <code>AfterViewInit</code> interfaces are removed from the code and <code>ctrl-alt-O</code> is pressed again.</p>\n<p>This time, <strong>Optimize imports</strong> automatically removes the unused interfaces from the import statement because they are no longer used in the code:</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/150813932005-optimize-imports-ctrl-alt-o.gif\" alt=\"Optimize imports\" width=\"1024\" height=\"576\" class=\"aligncenter size-large wp-image-160694\" /></p>\n<p>Don’t ever worry about your import statements again. WebStorm is smart enough to handle them for you!</p>\n<h2 id=\"summary\">Summary</h2>\n<p>Let’s recap Jurgen’s personal tips for increasing Angular development productivity in WebStorm:</p>\n<ol>\n<li><strong>Use Angular CLI from within WebStorm</strong> to quickly generate new Angular projects and features</li>\n<li><strong>Navigate like a pro</strong> to instantly jump to code definitions and easily locate code or files you are looking for</li>\n<li><strong>Take advantage of Angular Language Service</strong> to get even better code completion and error checking without compiling your Angular project</li>\n<li><strong>Auto-format your code</strong> to let WebStorm format all your code according to your project settings</li>\n<li><strong>Optimize your imports</strong> to ensure all unused imports are removed and your generated bundle size remains optimal </li>\n</ol>\n<p>In the next part, Todd Motto shares his favorite tips, so stay tuned for more!</p>\n","protected":false},"excerpt":{"rendered":"<p class=\"wp-special\"><em>This article was sponsored by <a href=\"https://www.jetbrains.com/\" rel=\"nofollow\">JetBrains</a>. Thank you for supporting the partners who make SitePoint possible.</em></p>\n<p>In this 2-part series, Google Developer Experts <a href=\"https://twitter.com/jvandemo\">Jurgen Van de Moere</a> and <a href=\"https://twitter.com/toddmotto\">Todd Motto</a> share their favorite productivity tips for developing Angular applications using WebStorm.</p>\n<p>In this first part, Jurgen shares his personal top 5 <a href=\"https://www.jetbrains.com/webstorm/\">WebStorm</a> features that allow him to increase his productivity on a daily basis:</p>\n<ol>\n<li>Use <a href=\"https://cli.angular.io/\">Angular CLI</a> from within <a href=\"https://www.jetbrains.com/webstorm/\">WebStorm</a></li>\n<li>Navigate like a pro</li>\n<li>Take advantage of <a href=\"https://next.angular.io/guide/language-service\">Angular Language Service</a></li>\n<li>Auto format your code</li>\n<li>Optimize your imports</li>\n</ol>\n<p>Each tip can tremendously increase your development productivity, so let’s dig into them a little deeper one by one.</p>\n<h2 id=\"tip1useangularclifromwithinwebstorm\">Tip 1: Use Angular CLI from Within WebStorm</h2>\n<p><a href=\"https://cli.angular.io/\">Angular CLI</a> is a Command Line Interface (CLI), written and maintained by the Angular team, to help automate your development workflow. You can use it to quickly create new Angular projects and add new features such as components, services and directives to existing Angular projects.</p>\n<p>WebStorm’s integration with Angular CLI provides you with all its power right from within WebStorm, without using the terminal.</p>\n<p>To create a new Angular Project, choose <strong>File | New | Project</strong> and select <strong>Angular CLI</strong>.</p>\n<p>Enter a project location and hit the <strong>Create</strong> button. WebStorm uses Angular CLI to create a new Angular project and install dependencies.</p>\n<p>When your new Angular application is in place, you can easily add new Angular features. Right click on <code>src/app</code> and choose <strong>New | Angular CLI</strong> to pick the type of feature you wish to add.</p>\n<p>Once you’ve selected a feature, you can specify the name and optional parameters, just as you would with Angular CLI on the command line:</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/150813951101-generate-new-project.gif\" alt=\"Create a new Angular module\" width=\"1024\" height=\"576\" class=\"aligncenter size-large wp-image-160696\" /></p>\n<blockquote>\n<p>To learn more about Angular CLI options and parameters, make sure to check out <a href=\"https://www.sitepoint.com/ultimate-angular-cli-reference/\">The Ultimate Angular CLI Reference</a>.</p>\n</blockquote>\n<p>What’s really awesome is that WebStorm automatically adds the component to the right Angular module for you, in this case <code>AppModule</code>.</p>\n<p>If your application has multiple Angular modules, right click on the module you wish to add the feature to and choose <strong>New | Angular CLI</strong>. WebStorm will make sure the new files are created in the right location and that the new feature is added to the correct Angular module.</p>\n<p>How sweet is that!</p>\n<h2 id=\"tip2navigatelikeapro\">Tip 2: Navigate Like a Pro</h2>\n<p>Use <code>cmd-click</code> or <code>cmd-B</code> to easily jump to any definition within your project.</p>\n<p>If you are a keyboard user, just put your cursor on a term and hit <code>cmd-B</code>. If you are a mouse user, hold down the <code>cmd</code> button and all terms you hover will turn into links to their definition.</p>\n<p>WebStorm automatically recognizes Angular components and directives in your HTML, links to stylesheets, links to templates, classes, interfaces and much more.</p>\n<p>No need to open file(s) manually, just jump to any definition you need:</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/150813900202-cmd-click.gif\" alt=\"Command-click words\" width=\"1024\" height=\"576\" class=\"aligncenter size-large wp-image-160682\" /></p>\n<p>When looking for a file that you don’t have an immediate reference to, hit <code>shift</code> twice to open the <strong>Search everywhere</strong> dialog. You don’t have to type the entire search string. If you want to open <code>AppComponent</code>, just type the first letter of each part — i.e. <code>ac</code> — and WebStorm will immediately narrow down the result list for you, so you can quickly pick the suggestion you wish to open:</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/150813903302-search-everywhere-1024x614.png\" alt=\"Search everywhere\" width=\"1024\" height=\"614\" class=\"aligncenter size-large wp-image-160683\" /></p>\n<p>Another super useful navigation shortcut is <code>cmd-E</code>, which presents you with a list of recently edited files so you can easily navigate back and forth between them.</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/150813905402-recent-files-1024x606.png\" alt=\"Recent files\" width=\"1024\" height=\"606\" class=\"aligncenter size-large wp-image-160684\" /></p>\n<p>Knowing how to quickly navigate to the code you need will save you a tremendous amount of time every single day.</p>\n<h2 id=\"tip3takeadvantageofangularlanguageservice\">Tip 3: Take Advantage of Angular Language Service</h2>\n<p><a href=\"https://next.angular.io/guide/language-service\">Angular Language Service</a> is a service, designed by the Angular Team, to provide IDEs with error checking and type completion within Angular templates.</p>\n<p>WebStorm integrates with Angular Language Service to better understand your code. To enable Angular Language Service, first make sure it is installed:</p>\n<pre><code class=\"bash language-bash\">npm install @angular/language-service --save-dev \r\n</code></pre>\n<blockquote>\n<p>If you use Angular CLI to generate an Angular application, Angular Language Service is automatically installed.</p>\n</blockquote>\n<p>Next, go to <strong>Preferences | Languages & Frameworks | TypeScript</strong>, make sure <strong>Use TypeScript Service</strong> is checked and click <strong>Configure…</strong>:</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/150813907803-configure-typescript-service-1024x710.png\" alt=\"TypeScript recommendations\" width=\"1024\" height=\"710\" class=\"aligncenter size-large wp-image-160685\" /></p>\n<p>The <strong>Service Options</strong> modal will pop up. Enable <strong>Use Angular service</strong> and apply the changes:</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/150813909603-enable-angular-service.png\" alt=\"TypeScript recommendations\" width=\"576\" height=\"464\" class=\"aligncenter size-full wp-image-160686\" /></p>\n<p>By default, WebStorm already provides great assistance for writing Angular code.</p>\n<p>When editing a script, WebStorm automatically imports the required JavaScript modules so you don’t have to import them manually.</p>\n<p>If you open up the TypeScript panel, WebStorm provides you with immediate feedback on the validity of your code, so you can quickly resolve issues before having to compile your project.</p>\n<p>Watch how the <code>OnInit</code> interface is automatically imported and how the live TypeScript feedback immediately tells you whether or not your TypeScript code is valid: </p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/150813912103-language-services.gif\" alt=\"TypeScript recommendations\" width=\"1024\" height=\"576\" class=\"aligncenter size-large wp-image-160687\" /></p>\n<p>When you edit a template, WebStorm provides you with smart code completion that recognizes components, directives and even input and output properties:</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/150813915203-autocomplete-in-templates.gif\" alt=\"Code completion in templates\" width=\"1024\" height=\"576\" class=\"aligncenter size-large wp-image-160688\" /></p>\n<p>With Angular Language Service enabled, WebStorm is able to improve code completion in template expressions:</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/150813919003-template-expressions.gif\" alt=\"Angular Language Service Expression Error\" width=\"1024\" height=\"576\" class=\"aligncenter size-large wp-image-160689\" /></p>\n<p>… and report template errors more precisely right inside your editor:</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/150813921503-highlighted-errors-1024x612.png\" alt=\"Highlighted errors\" width=\"1024\" height=\"612\" class=\"aligncenter size-large wp-image-160690\" /></p>\n<p>Catching errors without having to compile your project saves you incredible amounts of time.</p>\n<h2 id=\"tip4autoformatyourcode\">Tip 4: Auto-format Your Code</h2>\n<p>Don’t worry about formatting your code manually. WebStorm has you covered.</p>\n<p>Whether your are in a template, a script, a stylesheet or even a JSON file, just hit <code>cmd-option-L</code> and WebStorm will automatically format all code for you:</p>\n","protected":false},"author":72299,"featured_media":160679,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[768,407],"tags":[6152,9796,6494,9553,874,6298,11579],"_links":{"self":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/posts/160675"}],"collection":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/posts"}],"about":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/types/post"}],"author":[{"embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/users/72299"}],"replies":[{"embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/comments?post=160675"}],"version-history":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/posts/160675/revisions"}],"wp_featuredmedia":[{"embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/media/160679"}],"wp_attachment":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/media?parent=160675"}],"wp_term":[{"taxonomy":"category","embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/categories?post=160675"},{"taxonomy":"post_tag","embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/tags?post=160675"}],"curies":[{"name":"wp","href":"https://api.w.org/{rel}","templated":true}]}}
{"index":{"_index":"blogs","_id":160783,"_type":"default"}}
{"id":160783,"date":"2017-10-19T09:00:57","date_gmt":"2017-10-19T16:00:57","guid":{"rendered":"https://www.sitepoint.com/?p=160783"},"modified":"2017-10-18T23:55:49","modified_gmt":"2017-10-19T06:55:49","slug":"user-research-getting-the-right-people","status":"publish","type":"post","link":"https://www.sitepoint.com/user-research-getting-the-right-people/","title":{"rendered":"How to Conduct User Research: Getting the Right People"},"content":{"rendered":"<p><em>The following is a short extract from our new book, <a href=\"https://www.sitepoint.com/premium/books/researching-ux-user-research\">Researching UX: User Research</a>, written by James Lang and Emma Howell. It’s the ultimate guide to user research, a key part of effective UX design. SitePoint Premium members get access with their membership, or you can buy a copy in stores worldwide.</em></p>\n<p>Once you’ve decided who you want to include in the research, and defined it in a recruitment brief, you’ll need a way to ensure that you’re <em>actually</em> getting those people. There are two ways to do this.</p>\n<ul>\n<li><strong>Evaluating against the recruitment brief:</strong> Once you’ve identified a potential participant, you just size them up against the criteria in the recruitment brief, based on what you know about them or an informal conversation. This is the rough-and-ready method, and is most commonly used in DIY recruitment (see later in this chapter).</li>\n<li><strong>Using a screener:</strong> Once a potential participant has been identified, they’re asked a series of questions that evaluates them against the criteria in the recruitment brief, and allocates them to a quota. This is the more robust, credible approach, as used by recruitment agencies.</li>\n</ul>\n<p>There are pros and cons to both approaches. Evaluating against the recruitment brief can be inaccurate, risking misleading results and undermining the credibility of your project. On the other hand, a screener takes additional time to create and apply.</p>\n<p>There are some workarounds. If you hire a recruitment agency, they will often write the screener on your behalf. If you’re conducting guerrilla research, the screener will be very short. We’ll say more about both of these scenarios later in the chapter.</p>\n<h3 id=\"creating-a-screener\">Creating a Screener</h3>\n<p>A screener is a set of questions that are asked to potential participants, based on the sample criteria you defined in your recruitment brief. These questions are designed to figure out how suitable participants are for your project. </p>\n<p>You can see an <a href=\"https://docs.google.com/spreadsheets/d/1bwHwreXqDLgOGIKfhKPeN7ML4E5Ict5IITLBIO9yqPs/edit?usp=sharing\">example screener here</a>, showing the key questions you would want to ask to recruit for a project about outdoor gear. It establishes what activities the potential participants do without leading them to give certain answers. The other questions are written to probe more into their experiences and habits when buying outdoor equipment, without being leading. The final question is written to catch out anyone that is trying to trick their way onto the research.</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508337033screenertemplate.jpg\" alt=\"\" width=\"1476\" height=\"917\" class=\"aligncenter size-full wp-image-160784\" /></p>\n<p>Screener questions contain several elements:</p>\n<ul>\n<li>A question number.</li>\n<li>The question itself – This should be phrased as it would be read, even though in practice you should expect a little flexibility in the way a recruiter reads out the text you’ve written.</li>\n<li>Instructions to the recruiter. These won’t be read out, but give guidance on how to ask the question and how to classify the response. Common instructions include ‘Read out all options’, ‘Don’t read out options’, ‘Tick one’, ‘Tick all that apply’.</li>\n<li>A response area: normally multiple choice options, or an empty box for writing in. For each, there should be an instruction on what to do if it’s ticked, eg, ‘Thank and close’ (ie, reject the candidate and end the screener), ‘Recruit to quota’, or just ‘Continue’.</li>\n</ul>\n<p>As you can see, screeners have a certain amount of jargon attached to them, but you shouldn’t worry about this. If you’re doing your own recruitment, you just need to make it clear to yourself, while if you’re using a recruiter, they will be able to interpret your instructions once you’ve talked them through it.</p>\n<p>Some tips for creating a good screener:</p>\n<ul>\n<li>Use <strong>precise</strong> language. For example, rather than asking ,”How many times have you been to the cinema recently?”, a better question would be: ‘How many times have you been to the cinema in the past 30 days?”</li>\n<li>Try to make your questions as <strong>factual</strong> as possible, so participants aren’t tempted to exaggerate or misrepresent their behaviour. For example, if you want to know how frequently someone exercises, don’t ask them, “How many times do you exercise a week?” People will tend to exaggerate because they don’t want to look bad! A better question would be: “Which of the following have you done in the past week: running, cycling, gym, cinema, reading, etc.”</li>\n<li>Try to make your questions <strong>easy to answer</strong>. In particular, it can be hard to remember events that took place a long time ago. You can prompt with options, as in the example above, but make sure you disguise the answer you’re interested in among other choices.</li>\n<li>Make sure your questions are <strong>essential</strong> to selecting the best participants. The more questions you add, the more time consuming it is for you and the people you are screening. </li>\n<li>The <strong>ideal order</strong> to sequence your questions is to cover screening criteria first, then primary quotas, then secondary quotas, and finally information capture for contact details.</li>\n<li>In most cases, it’s a good idea to <strong>conceal the purpose of the research and the organisation you’re working for</strong>. The participant will probably guess to some extent, based on the questions you’re asking, but try to keep the details hidden. Otherwise, they may be tempted to do some prior reading up before attending the research session.</li>\n<li>Finally, try to focus on and <strong>categorise people based on behaviour</strong> if you can. If not, ask about attitudes. Demographics are least useful of all.</li>\n</ul>\n<p>It’s also important that you give potential participants some briefing information about the session during the screening process. For example:</p>\n<ul>\n<li>Telling them they’ll be asked to use a website or app.</li>\n<li>Reminding them to bring their glasses, if they need to.</li>\n<li>Asking them to bring a form of photo identification.</li>\n<li>Confirming the incentive and how it will be paid.</li>\n<li>Making sure they’ve got a contact number in case of any problems finding the venue or last-minute cancellations.<br />\n Giving this information ensures that participants are making an informed decision about whether to participate, and there are no nasty surprises on the day.</li>\n</ul>\n<div class=\"box tip\">\n<h4>Look Out for Professional Research Participants</h4>\n<div class=\"body\">\n<p>If you are screening people yourself, keep in mind that there are some people who will try and say whatever they think they need to say to get a place on your research. Incentives can be very alluring! To avoid this, include a question designed to catch out those individuals that are not being entirely truthful.</p>\n<p>Let’s take our example of a project for an outdoor equipment company. In the brief, we have asked for all of our participants to have visited of at least two of the big brands. One of your screener questions could be:</p>\n<p><em>Out of the following UK brands, which have you visited during the past six months?</em></p>\n<ul>\n<li><em>Go Outdoors</em></li>\n<li><em>Snow + Rock</em></li>\n<li><em>Ellis Brigham</em></li>\n<li><em>Hiking Gear R Us</em></li>\n</ul>\n<p>Hiking Gear R Us are our invented brand, so you can be sure that anyone who picks this screener should not be included in your fieldwork.</p>\n</p></div>\n</p></div>\n<h4 id=\"different-kinds-of-screeners\">Different Kinds of Screeners</h4>\n<p>Screeners vary in length and complexity. A typical screener for a depth interview or user test is around 10 – 30 questions long. This allows you to capture one or two primary variables, up to 7 secondary variables, plus capture contact details. Any longer than this, and you’ll find that candidates lose interest.</p>\n<p>If you’re conducting guerrilla research, your time is extremely limited. You’ll want to get screening over with as quickly as possible, which means five questions in total is plenty. Incidentally, that’s about as much as you can fit onto a single side of paper on a clipboard, so there are practical reasons for keeping it short, too.</p>\n<p>Finally, you may choose to run your screener as an online survey, and have candidates complete it themselves rather than talk them through it. If you take this approach, it’s important to:</p>\n<ul>\n<li>Put even more thought into the phrasing of your questions.</li>\n<li>Keep it short – no more than two or three minutes.</li>\n<li>Pilot test your questionnaire with at least three people before you launch it.<br />\n On the plus side, this is a great way to save time, especially if you’re sourcing people online from websites like Gumtree or Facebook.</li>\n</ul>\n","protected":false},"excerpt":{"rendered":"<p><em>The following is a short extract from our new book, <a href=\"https://www.sitepoint.com/premium/books/researching-ux-user-research\">Researching UX: User Research</a>, written by James Lang and Emma Howell. It’s the ultimate guide to user research, a key part of effective UX design. SitePoint Premium members get access with their membership, or you can buy a copy in stores worldwide.</em></p>\n<p>Once you’ve decided who you want to include in the research, and defined it in a recruitment brief, you’ll need a way to ensure that you’re <em>actually</em> getting those people. There are two ways to do this.</p>\n<ul>\n<li><strong>Evaluating against the recruitment brief:</strong> Once you’ve identified a potential participant, you just size them up against the criteria in the recruitment brief, based on what you know about them or an informal conversation. This is the rough-and-ready method, and is most commonly used in DIY recruitment (see later in this chapter).</li>\n<li><strong>Using a screener:</strong> Once a potential participant has been identified, they’re asked a series of questions that evaluates them against the criteria in the recruitment brief, and allocates them to a quota. This is the more robust, credible approach, as used by recruitment agencies.</li>\n</ul>\n<p>There are pros and cons to both approaches. Evaluating against the recruitment brief can be inaccurate, risking misleading results and undermining the credibility of your project. On the other hand, a screener takes additional time to create and apply.</p>\n<p>There are some workarounds. If you hire a recruitment agency, they will often write the screener on your behalf. If you’re conducting guerrilla research, the screener will be very short. We’ll say more about both of these scenarios later in the chapter.</p>\n<h3 id=\"creating-a-screener\">Creating a Screener</h3>\n<p>A screener is a set of questions that are asked to potential participants, based on the sample criteria you defined in your recruitment brief. These questions are designed to figure out how suitable participants are for your project. </p>\n<p>You can see an <a href=\"https://docs.google.com/spreadsheets/d/1bwHwreXqDLgOGIKfhKPeN7ML4E5Ict5IITLBIO9yqPs/edit?usp=sharing\">example screener here</a>, showing the key questions you would want to ask to recruit for a project about outdoor gear. It establishes what activities the potential participants do without leading them to give certain answers. The other questions are written to probe more into their experiences and habits when buying outdoor equipment, without being leading. The final question is written to catch out anyone that is trying to trick their way onto the research.</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508337033screenertemplate.jpg\" alt=\"\" width=\"1476\" height=\"917\" class=\"aligncenter size-full wp-image-160784\" /></p>\n<p>Screener questions contain several elements:</p>\n","protected":false},"author":72597,"featured_media":160841,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[6131,412,8601],"tags":[1093,1287,9506,11007,1097,10549],"_links":{"self":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/posts/160783"}],"collection":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/posts"}],"about":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/types/post"}],"author":[{"embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/users/72597"}],"replies":[{"embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/comments?post=160783"}],"version-history":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/posts/160783/revisions"}],"wp_featuredmedia":[{"embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/media/160841"}],"wp_attachment":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/media?parent=160783"}],"wp_term":[{"taxonomy":"category","embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/categories?post=160783"},{"taxonomy":"post_tag","embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/tags?post=160783"}],"curies":[{"name":"wp","href":"https://api.w.org/{rel}","templated":true}]}}
{"index":{"_index":"blogs","_id":160516,"_type":"default"}}
{"id":160516,"date":"2017-10-19T08:30:25","date_gmt":"2017-10-19T15:30:25","guid":{"rendered":"https://www.sitepoint.com/?p=160516"},"modified":"2017-10-17T17:28:16","modified_gmt":"2017-10-18T00:28:16","slug":"how-to-create-custom-components-using-component-io","status":"publish","type":"post","link":"https://www.sitepoint.com/how-to-create-custom-components-using-component-io/","title":{"rendered":"How to Create Custom Components Using Component IO"},"content":{"rendered":"<p>My <a href=\"https://www.sitepoint.com/an-introduction-to-component-io/\">Introduction to Component IO</a> article described how you could use pre-built components on any site regardless of the Content Management System, languages, or technologies used. The benefits include:</p>\n<ul>\n<li>hundreds of ready-made, attractive and configurable components to choose from including content blocks, galleries, navigation bars, social media widgets, forms and more</li>\n<li>component code can be installed with a simple cut and paste</li>\n<li>the same components can be used across other pages and sites will updated instantly</li>\n<li>it’s easy for non-technical editors to make changes in a WYSIWYG editor and check it with a live preview</li>\n<li>all users can share Component IO dashboard links and collaborate on the same items</li>\n<li>Component IO is fast and delivers items quickly with a single API call, regardless of the number embedded in the page</li>\n<li>you can switch CMS or build processes at any point and retain components</li>\n<li>a full help guide and real-time chat assistance is available</li>\n<li>a <a href=\"https://component.io/\">free trial account</a> can be used to test the service with your system.</li>\n</ul>\n<h2 id=\"componentiocustomcomponents\">Component IO Custom Components</h2>\n<p>Despite the huge range available, Component IO permits developers to create and edit their own components. In this tutorial, I will illustrate how to create a simple custom bar chart component which can be displayed and configured on any site:</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/150752844101-barchart.png\" alt=\"example bar chart\" width=\"400\" height=\"114\" class=\"aligncenter size-full wp-image-160520\" /></p>\n<h2 id=\"componentdevelopmentconcepts\">Component Development Concepts</h2>\n<p>Component IO uses the <a href=\"https://vuejs.org/\">Vue.js</a> component model. Those with experience with the framework will immediately recognize the concepts and syntax. That said, I’m no Vue.js expert — but a little HTML, CSS and JavaScript knowledge is enough to build a complex component.</p>\n<p>All components are encapsulated; their styles and code cannot ‘leak’ to other parts of the page. For example, the bar chart component’s title is an <code>H2</code> element and we can apply any styles, e.g.</p>\n<pre><code class=\"css language-css\">h2 {\r\n font-family: comic-sans;\r\n font-size: 8em;\r\n color: #f00;\r\n}\r\n</code></pre>\n<p>Vue.js will ensure those <em>(awful!)</em> styles are only applied to our component and not <code>H2</code> headings elsewhere on the page. However, a style applied to all <code>H2</code> titles on the page can cascade to our component title. This can be useful since our component can inherit default fonts, colors and dimensions.</p>\n<h2 id=\"step1createablankcomponent\">Step 1: Create a Blank Component</h2>\n<p>Log in to <a href=\"https://component.io/\">component.io</a>, and then click <strong>Blank component</strong> on the <strong>Project</strong> page:</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/150752846502-newcomponent.png\" alt=\"create a new component\" width=\"476\" height=\"318\" class=\"aligncenter size-full wp-image-160521\" /></p>\n<p>From the <strong>Edit</strong> menu, choose <strong>Edit component name</strong> and enter <em>“barchart”</em> or another suitable name.</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/150752848603-editmenu.png\" alt=\"edit menu\" width=\"475\" height=\"361\" class=\"aligncenter size-full wp-image-160522\" /></p>\n<h2 id=\"step2definefields\">Step 2: Define Fields</h2>\n<p>Fields are used to configure a component. They allow:</p>\n<ol>\n<li>Content editors to modify values.</li>\n<li>Other components to be created with a different configuration. For example, if we require two bar charts, we can duplicate the first and change the field values accordingly.</li>\n</ol>\n<p>From the <strong>Edit</strong> menu, choose <strong>Add / remove fields</strong> and enter the fields you require:</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/150752851604-addfields.png\" alt=\"add and remove fields\" width=\"748\" height=\"903\" class=\"aligncenter size-full wp-image-160523\" /></p>\n<p>For this control, I defined:</p>\n<ol>\n<li>A single <strong>title</strong> text field.</li>\n<li>The <strong>barvalue</strong> numeric field which defines the bar’s value.</li>\n<li>The <strong>barlabel</strong> text field which defines the bar’s label.</li>\n<li>The <strong>barcolor</strong> color field which defines the bar’s color.</li>\n</ol>\n<p>These last three items had the <strong>repeat</strong> checkbox checked. We can therefore define any number of data items in our bar chart.</p>\n<h2 id=\"step3settheinitialdata\">Step 3: Set the Initial Data</h2>\n<p>Hit the <strong>Edit</strong> menu to open the Content and Code control. Remaining in the <strong>Content</strong> section, I entered values for the title and three data items:</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/150752853505-setdata.png\" alt=\"set field data\" width=\"448\" height=\"752\" class=\"aligncenter size-full wp-image-160524\" /></p>\n<h2 id=\"step4definethecomponentcode\">Step 4: Define the Component Code</h2>\n<p>Hit the <strong>Code</strong> toggle to open the code editor. This is where the component’s HTML, CSS and JavaScript is defined:</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/150752855106-code.png\" alt=\"code editor\" width=\"762\" height=\"488\" class=\"aligncenter size-full wp-image-160525\" /></p>\n<p>The <a href=\"https://guide.component.io/v1/api/component-html.html\">component HTML documentation</a> describes how templates are created. There is no need for an outer <code>DIV</code> or other element because the component will be automatically given one.</p>\n<p>The title field is added first:</p>\n<pre><code class=\"markup language-markup\"><h2 v-text=\"title\"></h2>\r\n</code></pre>\n<p>Alternatively, we could use:</p>\n<pre><code class=\"markup language-markup\"><h2>{{ title }}</h2>\r\n</code></pre>\n<p>The chart bars will be contained in a <code><ul></code> list element where each <code><li></code> displays a single value. The HTML code:</p>\n<pre><code class=\"markup language-markup\"><ul>\r\n <li v-for=\"item in items\" :style=\"item.style\">\r\n <span>{{ item.barlabel }} \r\n <strong>{{ item.barpc }}</strong>\r\n </span>\r\n </li>\r\n</ul>\r\n</code></pre>\n<p><code>v-for</code> renders the <code><li></code> element multiple times depending on the repeating source data (it is assigned to the <code>items</code> array). Note that I have not defined fields for <code>item.style</code> and <code>item.barpc</code> at this stage since they will be calculated in JavaScript code.</p>\n<p>The <a href=\"https://guide.component.io/v1/api/component-css.html\">component CSS</a> can now be defined. This will only be applied to the component itself and not any other page elements. Sass SCSS syntax can be adopted for variables, nesting and other functions but I’ve kept it simple here:</p>\n<pre><code class=\"css language-css\">h2 {\r\n font-weight: normal;\r\n}\r\n\r\nul {\r\n padding: 2px 0;\r\n margin: 1em 0;\r\n list-style-type: none;\r\n border-left: 1px solid #666;\r\n}\r\n\r\nli {\r\n line-height: 1.2;\r\n padding: 1px 4px;\r\n margin: 0 0 1px 0;\r\n}\r\n\r\nspan {\r\n display: block;\r\n color: #888;\r\n mix-blend-mode: difference;\r\n}\r\n\r\nstrong {\r\n float: right;\r\n font-size: 0.8em;\r\n font-weight: normal;\r\n line-height: 1.5;\r\n}\r\n</code></pre>\n<p>Note that I have not set font styles or sizes so the component can inherit these from the page where it is used.</p>\n<p>Each Component IO component is a Vue.js instance and can use <a href=\"https://guide.component.io/v1/api/component-js.html\">the standard JavaScript properties and methods</a>. For example:</p>\n<ul>\n<li><code>component.data</code> holds field values such as <code>component.data.title</code> and <code>component.data.items[0].barlabel</code>. If we change a value, it will be instantly updated in the component.</li>\n<li>the <code>component.mounted</code> method is called as soon as the component has been rendered.</li>\n</ul>\n<p>The barchart component requires initialization code to calculate:</p>\n<ol>\n<li>the sum of all bar values (<code>totValue</code>), and</li>\n<li>the highest value (<code>maxValue</code>). This will have a bar which uses 100% of the available space.</li>\n</ol>\n<pre><code class=\"javascript language-javascript\">// initialisation\r\nlet \r\n items = component.data.items,\r\n totValue = 0, maxValue = 0;\r\n\r\nfor (let i = 0; i < items.length; i++) {\r\n totValue += items[i].barvalue;\r\n maxValue = Math.max(maxValue, items[i].barvalue);\r\n items[i].style = '';\r\n}\r\n</code></pre>\n<p>The <code>component.mounted</code> method can now calculate each bar’s percentage and create the bar lengths using a CSS background linear-gradient:</p>\n<pre><code class=\"javascript language-javascript\">// component created\r\ncomponent.mounted = function() {\r\n\r\n for (let i = 0; maxValue && i < items.length; i++) {\r\n\r\n let \r\n color = items[i].barcolor || '#888',\r\n pc = Math.round(items[i].barvalue / maxValue * 100);\r\n\r\n // calculate bar percentage\r\n items[i].barpc = (Math.round(items[i].barvalue / totValue * 100)) + '%';\r\n\r\n // set bar style\r\n items[i].style = 'background-image:linear-gradient(90deg,' + color + ' ' + \r\n pc + '%,transparent ' + pc + '%,transparent ' + (100 - pc) + '%);';\r\n }\r\n\r\n};\r\n</code></pre>\n<p>Hit <strong>Save</strong> (or press Ctrl + S) and close the editor using the <strong>X</strong> at the top-left.</p>\n<h2 id=\"step5previewyourcomponent\">Step 5: Preview Your Component</h2>\n<p>All going well, the component is now rendered as expected:</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/150752857107-preview.png\" alt=\"rendered component\" width=\"587\" height=\"274\" class=\"aligncenter size-full wp-image-160526\" /></p>\n<p>You can change field data to see how it affects the component.</p>\n<p>If anything fails, open your browser developer tools (<strong>F12</strong> or <strong>Ctrl|Cmd + Shift + I</strong>) and examine any error messages in the console. The <a href=\"https://guide.component.io/\">Component IO Guide</a> provides further information about APIs and using code within other frameworks.</p>\n<h2 id=\"step6installthecomponentonyoursite\">Step 6: Install the Component on Your Site</h2>\n<p>The component can be installed on any website where you are able to insert HTML code (a system such as <a href=\"https://codepen.io/\">CodePen.io</a> is ideal). Hit the <strong>Install</strong> button to view the instructions.</p>\n<p>The first component on the page will require both the component HTML, e.g.</p>\n<pre><code class=\"markup language-markup\"><component key=XXXXX></component>\r\n</code></pre>\n<p>… and the Component IO script (just before the closing <code></body></code> tag is ideal):</p>\n<pre><code class=\"markup language-markup\"><script project=\"YYYYY\" src=\"https://cdn.component.io/v1\"></script>\r\n</code></pre>\n<p>Subsequent components on that page just need their <code><component></code> tag.</p>\n<p data-height=\"300\" data-theme-id=\"6441\" data-slug-hash=\"QMYvLL\" data-default-tab=\"html,result\" data-user=\"craigbuckler\" data-embed-version=\"2\" data-pen-title=\"Component.io custom components\" class=\"codepen\">See the Pen <a href=\"https://codepen.io/craigbuckler/pen/QMYvLL/\">Component.io custom components</a> by Craig Buckler (<a href=\"https://codepen.io/craigbuckler\">@craigbuckler</a>) on <a href=\"https://codepen.io\">CodePen</a>.</p>\n<p><script async src=\"https://production-assets.codepen.io/assets/embed/ei.js\"></script></p>\n<p>Users will see an edit icon on the right-hand side of the page if they are logged in to their Component IO account. When they click the icon, they can choose one of the components and edit the field data or code.</p>\n<h2 id=\"cuecomponentizedworkflow\">Cue Componentized Workflow!</h2>\n<p>Custom components provides a flexible, modular development workflow for any website regardless of the CMS, server-side language, or technologies. Components can be shared, modified, duplicated and put live without a complicated build process or a rigid CMS plug-in system. You can be productive immediately without having to learn yet another web-based eco-system!</p>\n<p><a href=\"https://component.io/\">Component IO</a> provides a simple tool which could revolutionize how you approach new features and updates for clients. It’s easy to start with pre-built widgets then create your own component collection. <a href=\"https://component.io/\">Sign-up is free</a> – <em>you have nothing to lose!</em></p>\n","protected":false},"excerpt":{"rendered":"<p>My <a href=\"https://www.sitepoint.com/an-introduction-to-component-io/\">Introduction to Component IO</a> article described how you could use pre-built components on any site regardless of the Content Management System, languages, or technologies used. The benefits include:</p>\n<ul>\n<li>hundreds of ready-made, attractive and configurable components to choose from including content blocks, galleries, navigation bars, social media widgets, forms and more</li>\n<li>component code can be installed with a simple cut and paste</li>\n<li>the same components can be used across other pages and sites will updated instantly</li>\n<li>it’s easy for non-technical editors to make changes in a WYSIWYG editor and check it with a live preview</li>\n<li>all users can share Component IO dashboard links and collaborate on the same items</li>\n<li>Component IO is fast and delivers items quickly with a single API call, regardless of the number embedded in the page</li>\n<li>you can switch CMS or build processes at any point and retain components</li>\n<li>a full help guide and real-time chat assistance is available</li>\n<li>a <a href=\"https://component.io/\">free trial account</a> can be used to test the service with your system.</li>\n</ul>\n<h2 id=\"componentiocustomcomponents\">Component IO Custom Components</h2>\n<p>Despite the huge range available, Component IO permits developers to create and edit their own components. In this tutorial, I will illustrate how to create a simple custom bar chart component which can be displayed and configured on any site:</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/150752844101-barchart.png\" alt=\"example bar chart\" width=\"400\" height=\"114\" class=\"aligncenter size-full wp-image-160520\" /></p>\n<h2 id=\"componentdevelopmentconcepts\">Component Development Concepts</h2>\n<p>Component IO uses the <a href=\"https://vuejs.org/\">Vue.js</a> component model. Those with experience with the framework will immediately recognize the concepts and syntax. That said, I’m no Vue.js expert — but a little HTML, CSS and JavaScript knowledge is enough to build a complex component.</p>\n<p>All components are encapsulated; their styles and code cannot ‘leak’ to other parts of the page. For example, the bar chart component’s title is an <code>H2</code> element and we can apply any styles, e.g.</p>\n<pre><code class=\"css language-css\">h2 {\r\n font-family: comic-sans;\r\n font-size: 8em;\r\n color: #f00;\r\n}\r\n</code></pre>\n<p>Vue.js will ensure those <em>(awful!)</em> styles are only applied to our component and not <code>H2</code> headings elsewhere on the page. However, a style applied to all <code>H2</code> titles on the page can cascade to our component title. This can be useful since our component can inherit default fonts, colors and dimensions.</p>\n<h2 id=\"step1createablankcomponent\">Step 1: Create a Blank Component</h2>\n<p>Log in to <a href=\"https://component.io/\">component.io</a>, and then click <strong>Blank component</strong> on the <strong>Project</strong> page:</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/150752846502-newcomponent.png\" alt=\"create a new component\" width=\"476\" height=\"318\" class=\"aligncenter size-full wp-image-160521\" /></p>\n<p>From the <strong>Edit</strong> menu, choose <strong>Edit component name</strong> and enter <em>“barchart”</em> or another suitable name.</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/150752848603-editmenu.png\" alt=\"edit menu\" width=\"475\" height=\"361\" class=\"aligncenter size-full wp-image-160522\" /></p>\n<h2 id=\"step2definefields\">Step 2: Define Fields</h2>\n<p>Fields are used to configure a component. They allow:</p>\n<ol>\n<li>Content editors to modify values.</li>\n<li>Other components to be created with a different configuration. For example, if we require two bar charts, we can duplicate the first and change the field values accordingly.</li>\n</ol>\n<p>From the <strong>Edit</strong> menu, choose <strong>Add / remove fields</strong> and enter the fields you require:</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/150752851604-addfields.png\" alt=\"add and remove fields\" width=\"748\" height=\"903\" class=\"aligncenter size-full wp-image-160523\" /></p>\n<p>For this control, I defined:</p>\n<ol>\n<li>A single <strong>title</strong> text field.</li>\n<li>The <strong>barvalue</strong> numeric field which defines the bar’s value.</li>\n<li>The <strong>barlabel</strong> text field which defines the bar’s label.</li>\n<li>The <strong>barcolor</strong> color field which defines the bar’s color.</li>\n</ol>\n<p>These last three items had the <strong>repeat</strong> checkbox checked. We can therefore define any number of data items in our bar chart.</p>\n<h2 id=\"step3settheinitialdata\">Step 3: Set the Initial Data</h2>\n<p>Hit the <strong>Edit</strong> menu to open the Content and Code control. Remaining in the <strong>Content</strong> section, I entered values for the title and three data items:</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/150752853505-setdata.png\" alt=\"set field data\" width=\"448\" height=\"752\" class=\"aligncenter size-full wp-image-160524\" /></p>\n<h2 id=\"step4definethecomponentcode\">Step 4: Define the Component Code</h2>\n<p>Hit the <strong>Code</strong> toggle to open the code editor. This is where the component’s HTML, CSS and JavaScript is defined:</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/150752855106-code.png\" alt=\"code editor\" width=\"762\" height=\"488\" class=\"aligncenter size-full wp-image-160525\" /></p>\n<p>The <a href=\"https://guide.component.io/v1/api/component-html.html\">component HTML documentation</a> describes how templates are created. There is no need for an outer <code>DIV</code> or other element because the component will be automatically given one.</p>\n<p>The title field is added first:</p>\n<pre><code class=\"markup language-markup\"><h2 v-text=\"title\"></h2>\r\n</code></pre>\n<p>Alternatively, we could use:</p>\n<pre><code class=\"markup language-markup\"><h2>{{ title }}</h2>\r\n</code></pre>\n<p>The chart bars will be contained in a <code><ul></code> list element where each <code><li></code> displays a single value. The HTML code:</p>\n","protected":false},"author":515,"featured_media":160519,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[6523],"tags":[11155,8976,9553,6298],"_links":{"self":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/posts/160516"}],"collection":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/posts"}],"about":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/types/post"}],"author":[{"embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/users/515"}],"replies":[{"embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/comments?post=160516"}],"version-history":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/posts/160516/revisions"}],"wp_featuredmedia":[{"embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/media/160519"}],"wp_attachment":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/media?parent=160516"}],"wp_term":[{"taxonomy":"category","embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/categories?post=160516"},{"taxonomy":"post_tag","embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/tags?post=160516"}],"curies":[{"name":"wp","href":"https://api.w.org/{rel}","templated":true}]}}
{"index":{"_index":"blogs","_id":160833,"_type":"default"}}
{"id":160833,"date":"2017-10-18T14:54:17","date_gmt":"2017-10-18T21:54:17","guid":{"rendered":"https://www.sitepoint.com/?p=160833"},"modified":"2017-10-18T14:54:17","modified_gmt":"2017-10-18T21:54:17","slug":"git-and-wordpress-how-to-auto-update-posts-with-pull-requests","status":"publish","type":"post","link":"https://www.sitepoint.com/git-and-wordpress-how-to-auto-update-posts-with-pull-requests/","title":{"rendered":"Git and WordPress: How to Auto-Update Posts with Pull Requests"},"content":{"rendered":"<p>At <a href=\"https://bitfalls.com\">Bitfalls.com</a>, we also use WordPress for now, and use the same peer review approach for content as we do <a href=\"https://www.sitepoint.com/write-for-us/\">at SitePoint</a>. </p>\n<p>We decided to build a tool which automatically pulls content from merged pull requests into articles, giving us the ability to fix typos and update posts from Github, and see the changes reflected on the live site. This tutorial will walk you through the creation of this tool, so you can start using it for your own WordPress site, or build your own version.</p>\n\n<h2 id=\"theplan\">The Plan</h2>\n<p>The first part is identifying the problem and the situation surrounding it.</p>\n<ul>\n<li>we use WPGlobus for multi-language support, which means content gets saved like this: <code>{:en}English content{:}{:hr}Croatian content{:}</code>.</li>\n<li>authors submit PRs via Github, the PRs are peer reviewed and merged, and then (currently) manually imported into WP’s Posts UI through the browser.</li>\n<li>every post has the same folder layout: <code>author_folder/post_folder/language/final.md</code></li>\n<li>this is slow and error prone, and sometimes mistakes slip by. It also makes updating posts tedious.</li>\n</ul>\n<p>The solution is the following:</p>\n<ul>\n<li>add a hook processor which will detect pushes to the master branch (i.e. merges from PRs)</li>\n<li>the processor should look for a meta file in the commit which would contain information on where to save the updated content</li>\n<li>the processor automatically converts the MD content to HTML, merges the languages in the WPGlobus format, and saves them into the database</li>\n</ul>\n<h2 id=\"bootstrapping\">Bootstrapping</h2>\n<p>If you’d like to follow along (highly recommended), please boot up a <a href=\"http://www.sitepoint.com/quick-tip-get-homestead-vagrant-vm-running/\">good virtual machine environment</a>, install the newest version of WordPress on it, and add the WPGlobus plugin. Alternatively, you can use a prepared WordPress box like <a href=\"https://www.sitepoint.com/wordpress-meets-vagrant-vvv/\">VVV</a>. Additionally, make sure your environment has <a href=\"https://www.sitepoint.com/use-ngrok-test-local-site/\">ngrok</a> installed – we’ll use that to pipe Github hook triggers to our local machine, so we can test locally instead of having to deploy.</p>\n<h2 id=\"hooks\">Hooks</h2>\n<p>For this experiment, let’s create a new repository. I’ll call mine <a href=\"https://github.com/Swader/autopush\">autopush</a>.</p>\n<p>In the settings of this repository, we need to add a <a href=\"https://github.com/Swader/autopush/settings/hooks/new\">new hook</a>. Since we’re talking about a temporary Ngrok URL, let’s first spin that up. In my case, entering the following on the host machine does the trick:</p>\n<pre><code class=\"bash language-bash\">ngrok http homestead.app:80\r\n</code></pre>\n<p>I was given the link <code>http://03672a64.ngrok.io</code>, so that’s what goes into the webhook, with an arbitrary suffix like <code>githook</code>. We only need push events. The <code>json</code> data type is cleaner, so that’s selected as a preference, and the final webhook setup looks something like this:</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508224690Screenshot-2017-10-17-09.17.48.png\" alt=\"Webhook setup\" /></p>\n<p>Let’s test this now.</p>\n<pre><code class=\"bash language-bash\">git clone https://github.com/swader/autopush\r\ncd autopush\r\ntouch README.md\r\necho \"This is a README file\" >> README.md\r\ngit add -A\r\ngit commit -am \"We're pushing for the first time\"\r\ngit push origin master\r\n</code></pre>\n<p>The ngrok log screen should display something like this:</p>\n<pre><code class=\"bash language-bash\">POST /githook/ 404 Not Found\r\n</code></pre>\n<p>This is fine. We haven’t made the <code>/githook</code> endpoint yet.</p>\n<h2 id=\"processingwebhooks\">Processing Webhooks</h2>\n<p>We’ll read this new data into WordPress with custom logic. Due to the spaghetti-code nature of WP itself, it’s easier to circumvent it entirely with a small custom application. First, we’ll create the <code>githook</code> folder in the WordPress project’s root, and an <code>index.php</code> file inside it. This makes the <code>/githook/</code> path accessible, and the hook will no longer return 404, but 200 OK.</p>\n<p>According to the <a href=\"https://developer.github.com/v3/activity/events/types/#pushevent\">docs</a>, the payload will have a <code>commits</code> field with a <code>modified</code> field in each commit. Since we’re only looking to update posts, not schedule them or delete them – those steps are still manual, for safety – we’ll only be paying attention to that one. Let’s see if we can catch it on a test push.</p>\n<p>First, we’ll save our request data to a text file, for debugging purposes. We can do this by modifying our <code>githook/index.php</code> file:</p>\n<pre><code class=\"php language-php\"><?php\r\nfile_put_contents('test.txt', file_get_contents('php://input'));\r\n</code></pre>\n<p>Then we’ll create a new branch, add a file, and push it online.</p>\n<pre><code class=\"bash language-bash\">git checkout -b test-branch\r\ntouch testfile.md\r\ngit add testfile.md\r\ngit commit -am \"Added test file\"\r\ngit push origin test-branch\r\n</code></pre>\n<p>Sure enough, our <code>test.json</code> file is filled with the payload now. <a href=\"http://jsoneditoronline.org/?id=3d65c7107d3233d8660ebb7419bf3104\">This</a> is the payload I got. You can see that we have only one commit, and that commit’s <code>modified</code> field is empty, while the <code>added</code> field has <code>testfile.md</code>. We can also see this happened on <code>refs/heads/test-branch</code>, ergo, we’re not interested in it. But what happens if we make a PR out of this branch and merge it?</p>\n<p>Our payload looks <a href=\"http://jsoneditoronline.org/?id=78d6d3e59f0b6944cde0c8ae3ff5b023\">different</a>. Most notably, we now have <code>refs/heads/master</code> as the <code>ref</code> field, meaning it happened on the <code>master</code> branch and we <em>must</em> pay attention to it. We also have 2 commits instead of just one: the first one is the same as in the original PR, the adding of the file. The second one corresponds to the change on the master branch: the merging itself. Both reference the same <code>added</code> file.</p>\n<p>Let’s do one final test. Let’s edit <code>testfile.md</code>, push that, and do a PR and merge.</p>\n<pre><code class=\"bash language-bash\">echo \"Hello\" >> testfile.md\r\ngit add testfile.md\r\ngit commit -am \"Added test file\"\r\ngit push origin test-branch\r\n</code></pre>\n<p>Ahh, <a href=\"http://jsoneditoronline.org/?id=78d6d3e59f0b6944cde0c8ae3ff95d1e\">there we go</a>. We now have a modified file in the payload.</p>\n<p>Now let’s do a “real” scenario and simulate an update submission. First we’ll create a post’s default folder, and then we’ll PR an update into it.</p>\n<pre><code class=\"bash language-bash\">git checkout master\r\ngit pull\r\nmkdir -p authors/some-author/some-post/{en_EN,hr_HR,images}\r\necho \"English content\" >> authors/some-author/some-post/en_EN/final.md\r\necho \"Croatian content\" >> authors/some-author/some-post/hr_HR/final.md\r\ntouch authors/some-author/some-post/images/.gitkeep\r\ngit add -A\r\ngit commit -am \"Added some author\"\r\ngit push origin master\r\n</code></pre>\n<p>Then we do the edit.</p>\n<pre><code class=\"bash language-bash\">git checkout -b edit-for-some-post\r\necho \"This is a new line\" >> authors/some-author/some-post/en_EN/final.md\r\ngit add -A\r\ngit commit -am \"Added an update on the English version of the post\"\r\ngit push origin edit-for-some-post\r\n</code></pre>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508229112Screenshot-2017-10-17-10.31.01.png\" alt=\"New post edit PR suggested\" /></p>\n<p>If we turn this into a pull request in the Github web UI and merge the PR, we’ll get <a href=\"http://jsoneditoronline.org/?id=34653146cd548c1d9d164ad64e727fb4\">this payload</a>.</p>\n<p>If we follow the path from the modified files in the payload, we can easily discern the folder we’re talking about. Let’s modify the <code>index.php</code> file from before.</p>\n<pre><code class=\"php language-php\">$payload = json_decode($json, true);\r\n$last_commit = array_pop($payload['commits']);\r\n\r\n$modified = $last_commit['modified'];\r\n\r\n$prefix = 'https://raw.githubusercontent.com/';\r\n$repo = 'swader/autopush/master/';\r\n$lvl = 2;\r\n\r\n$folders = [];\r\nforeach ($modified as $file) {\r\n $folder = explode('/', $file);\r\n $folder = implode('/', array_slice($folder, 0, -$lvl));\r\n $folders[] = $folder;\r\n}\r\n$folders = array_unique($folders);\r\nvar_dump($folders);\r\n</code></pre>\n<p>We fetch the last commit in the payload, extract its modified files list, and find the parent folder of each modified file. The parent is dictated by the <code>$lvl</code> variable – in our case it’s 2 because the folder is 2 levels up: one extra for language (<code>en_EN</code>).</p>\n<p>And there we have it – the path of the folder that holds the files that need to be updated. Now all we have to do is fetch the contents, turn the Markdown of those files into HTML, and save it into the database.</p>\n<h2 id=\"processingmarkdown\">Processing Markdown</h2>\n<p>To process MarkDown, we can use the <a href=\"https://github.com/erusev/parsedown\">Parsedown</a> package. We’ll install these dependencies in the <code>githooks</code> folder itself, to make the app as standalone as possible.</p>\n<pre><code class=\"bash language-bash\">composer require erusev/parsedown\r\n</code></pre>\n<p>Parsedown is the same flavor of Markdown we use at Bitfalls while writing with the <a href=\"http://caret.io\">Caret</a> editor, so it’s a perfect match.</p>\n<p>Now we can modify <code>index.php</code> again.</p>\n<pre><code class=\"php language-php\">$payload = json_decode($json, true);\r\n$last_commit = array_pop($payload['commits']);\r\n\r\n$modified = $last_commit['modified'];\r\n\r\n$prefix = 'https://raw.githubusercontent.com/';\r\n$repo = 'swader/autopush/';\r\n$branch = 'master/';\r\n\r\n$languages = [\r\n 'en_EN' => 'en',\r\n 'hr_HR' => 'hr'\r\n];\r\n$lvl = 2;\r\n\r\n$folders = [];\r\nforeach ($modified as $file) {\r\n $folder = explode('/', $file);\r\n $folder = implode('/', array_slice($folder, 0, -$lvl));\r\n $folders[] = $folder;\r\n}\r\n$folders = array_unique($folders);\r\n\r\nforeach ($folders as $folder) {\r\n $fullFolderPath = $prefix.$repo.$branch.$folder.'/';\r\n $content = '';\r\n foreach ($languages as $langpath => $key) {\r\n $url = $fullFolderPath.$langpath.'/final.md';\r\n $content .= \"{:$key}\".mdToHtml(getContent($url)).\"{:}\";\r\n }\r\n if (!empty($content)) {\r\n // Save to database\r\n }\r\n}\r\n\r\nfunction getContent(string $url): string {\r\n $ch = curl_init();\r\n curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);\r\n curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);\r\n curl_setopt($ch, CURLOPT_URL, $url.'?nonce='.md5(microtime()));\r\n curl_setopt($ch, CURLOPT_FRESH_CONNECT, TRUE);\r\n $data = curl_exec($ch);\r\n $code = curl_getinfo($ch, CURLINFO_HTTP_CODE);\r\n if ($code != 200) {\r\n return '';\r\n }\r\n curl_close($ch);\r\n return $data;\r\n}\r\n\r\nfunction mdToHtml(string $text): string {\r\n $p = new Parsedown();\r\n $p->setUrlsLinked(true);\r\n return $p->parse($text);\r\n}\r\n</code></pre>\n<p>We made some really simple functions to avoid repetition. We also added a mapping of language folders (locales) to their WPGlobus keys, so that when iterating through all the files in a folder, we know how to delimit them in the post’s body. </p>\n<p><em>Note: we have to update all language versions of a post when doing an update to just one, because WPGlobus doesn’t use an extra field or a different database row to save another language of a post – it saves them all in one field, so the whole value of that field needs to be updated.</em></p>\n<p>We iterate through the folders that got updates (there might be more than one in a single PR), grab the contents of the file and convert it to HTML, then store all this into a WPGlobus-friendly string. Now it’s time to save this into the database.</p>\n<p><em>Note: we used a nonce at the end of the URL to invalidate a possible cache issue with raw github content.</em></p>\n<h2 id=\"savingeditedcontent\">Saving Edited Content</h2>\n<p>We have no idea where to save the new content. We need to add support for meta files.</p>\n<p>First, we’ll add a new function which gets this meta file:</p>\n<pre><code class=\"php language-php\">function getMeta(string $folder): ?array {\r\n $data = getContent(trim($folder, '/').'/meta.json');\r\n if (!empty($data)) {\r\n return json_decode($data, true);\r\n }\r\n return null;\r\n}\r\n</code></pre>\n<p>Simple, if it exists, it’ll return its contents. The meta files will be JSON, so all the parsing we’ll ever need is already built into PHP.</p>\n<p>Then, we’ll add a check to our main loop so that the process skips any folder without a meta file.</p>\n<pre><code class=\"php language-php\">foreach ($folders as $folder) {\r\n $fullFolderPath = $prefix.$repo.$branch.$folder.'/';\r\n\r\n $meta = getMeta($fullFolderPath);\r\n if (!$meta) {\r\n continue;\r\n }\r\n\r\n // ...\r\n</code></pre>\n<p>We’ll use the <a href=\"https://developer.wordpress.org/cli/commands/post/update/\">WP CLI</a> to make updates. The CLI can be installed with the following commands:</p>\n<pre><code class=\"bash language-bash\">curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar\r\nsudo mv wp-cli.phar /usr/local/bin/wp\r\nsudo chmod +x /usr/local/bin/wp\r\n</code></pre>\n<p>This downloads the WP-CLI tool, puts it into the server’s path (so it can be executed from anywhere), and adds “executable” permission to it.</p>\n<p>The <code>post update</code> command needs a post ID, and the field to update. WordPress posts are saved into the <code>wp_posts</code> database table, and the field we’re looking to update is the <code>post_content</code> field.</p>\n<p>Let’s try this out in the command line to make sure it works as intended. First we’ll add an example post. I gave it an example title of “Example post” in English and “Primjer” in Croatian, with the body <code>This is some English content for a post!</code> for the English content, and <code>Ovo je primjer!</code> for the Croatian content. When saved, this is what it looks like in the database:</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508250773Screenshot-2017-10-17-16.31.16.png\" alt=\"Example post in the database\" /></p>\n<p>In my case, the ID of the post is 428. If your WP installation is fresh, yours will probably be closer to 1.</p>\n<p>Now let’s see what happens if we execute the following on the command line:</p>\n<pre><code class=\"bash language-bash\">wp post update 428 --post_content='{:en}This is some English content for a post - edited!{:}{:hr}Ovo je primjer - editiran!{:}'\r\n</code></pre>\n<p>Sure enough, our post was updated.</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508251400Screenshot-2017-10-17-16.43.09.png\" alt=\"Updated post\" /></p>\n<p>This looks like it might become problematic when dealing with quotes which would need to be escaped. It’s better if we update from file, and let this tool handle the quotes and such. Let’s give it a try.</p>\n<p>Let’s put the content <code>:en}This is some English 'content' for a post - edited \"again\"!{:}{:hr}Ovo je 'primjer' - editiran \"opet\"!{:}</code> into a file called <code>updateme.txt</code>. Then…</p>\n<pre><code class=\"bash language-bash\">wp post update 428 updateme.txt\r\n</code></pre>\n<p>Yup, all good.</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508329677Screenshot-2017-10-18-14.27.25.png\" alt=\"Screenshot of update from file\" /></p>\n<p>Okay, now let’s add this into our tool.</p>\n<p>For now, our meta file will only have the ID of the post, so let’s add one such file to the content repo.:</p>\n<pre><code class=\"bash language-bash\">git checkout master\r\ngit pull\r\necho '{\"id\": 428}' >> authors/some-author/some-post/meta.json\r\ngit add -A\r\ngit commit -am \"Added meta file for post 428\"\r\ngit push origin master\r\n</code></pre>\n<p><em>Note: update the ID to match yours.</em></p>\n<p>At this point, our content repo should look like <a href=\"https://github.com/Swader/autopush/releases/tag/1\">this</a> (version saved as release, feel free to clone).</p>\n<p>Replace the <code>// Save to database</code> line in the code from before and its surrounding lines with:</p>\n<pre><code class=\"php language-php\"> if (!empty($content) && is_numeric($meta['id'])) {\r\n file_put_contents('/tmp/wpupdate', $content);\r\n exec('wp post update '.$meta['id'].' /tmp/wpupdate', $output);\r\n var_dump($output);\r\n }\r\n</code></pre>\n<p>We make sure that both content and the ID of the post to be updated are somewhat valid, and then we write the contents into a temporary file, from which we then feed it to the <code>wp cli</code> tool.</p>\n<p>We should also add some more checks to the beginning of the script to make sure we only execute the updates we want to execute:</p>\n<pre><code class=\"php language-php\">// ...\r\n\r\n$payload = json_decode($json, true);\r\n\r\nif (empty($json)) {\r\n header(\"HTTP/1.1 500 Internal Server Error\");\r\n die('No data provided for parsing, payload invalid.');\r\n}\r\n\r\nif ($payload['ref'] !== 'refs/heads/master') {\r\n die('Ignored. Not master.');\r\n}\r\n\r\n$last_commit = array_pop($payload['commits']);\r\n\r\n// ...\r\n</code></pre>\n<p>The full <code>index.php</code> file looks like this now:</p>\n<pre><code class=\"php language-php\"><?php\r\n\r\nrequire_once 'vendor/autoload.php';\r\n\r\n$json = file_get_contents('php://input');\r\nfile_put_contents('test.json', $json);\r\n$payload = json_decode($json, true);\r\n\r\nif (empty($json)) {\r\n header(\"HTTP/1.1 500 Internal Server Error\");\r\n die('No data provided for parsing, payload invalid.');\r\n}\r\n\r\nif ($payload['ref'] !== 'refs/heads/master') {\r\n die('Ignored. Not master.');\r\n}\r\n\r\n$last_commit = array_pop($payload['commits']);\r\n\r\n$modified = $last_commit['modified'];\r\n\r\n$prefix = 'https://raw.githubusercontent.com/';\r\n$repo = 'swader/autopush/';\r\n$branch = 'master/';\r\n\r\n$languages = [\r\n 'en_EN' => 'en',\r\n 'hr_HR' => 'hr'\r\n];\r\n$lvl = 2;\r\n\r\n$folders = [];\r\nforeach ($modified as $file) {\r\n $folder = explode('/', $file);\r\n $folder = implode('/', array_slice($folder, 0, -$lvl));\r\n $folders[] = $folder;\r\n}\r\n$folders = array_unique($folders);\r\n\r\nforeach ($folders as $folder) {\r\n $fullFolderPath = $prefix.$repo.$branch.$folder.'/';\r\n\r\n $meta = getMeta($fullFolderPath);\r\n if (!$meta) {\r\n continue;\r\n }\r\n\r\n $content = '';\r\n foreach ($languages as $langpath => $key) {\r\n $url = $fullFolderPath.$langpath.'/final.md';\r\n $content .= \"{:$key}\".mdToHtml(getContent($url)).\"{:}\";\r\n }\r\n if (!empty($content) && is_numeric($meta['id'])) {\r\n file_put_contents('/tmp/wpupdate', $content);\r\n exec('wp post update '.$meta['id'].' /tmp/wpupdate', $output);\r\n var_dump($output);\r\n }\r\n}\r\n\r\nfunction getContent(string $url): ?string {\r\n $ch = curl_init();\r\n curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);\r\n curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);\r\n curl_setopt($ch, CURLOPT_URL, $url.'?nonce='.md5(microtime()));\r\n curl_setopt($ch, CURLOPT_FRESH_CONNECT, TRUE);\r\n\r\n $data = curl_exec($ch);\r\n $code = curl_getinfo($ch, CURLINFO_HTTP_CODE);\r\n if ($code != 200) {\r\n return null;\r\n }\r\n curl_close($ch);\r\n return $data;\r\n}\r\n\r\nfunction mdToHtml(string $text): string {\r\n $p = new Parsedown();\r\n $p->setUrlsLinked(true);\r\n return $p->parse($text);\r\n}\r\n\r\nfunction getMeta(string $folder): ?array {\r\n $data = getContent(trim($folder, '/').'/meta.json');\r\n if (!empty($data)) {\r\n return json_decode($data, true);\r\n }\r\n return null;\r\n}\r\n</code></pre>\n<p>At this point, we can test things. Perfect chance for a brand new branch, too.</p>\n<pre><code class=\"bash language-bash\">git checkout -b post-update\r\necho 'Adding a new line yay!' >> authors/some-author/some-post/en_EN/final.md\r\ngit add -A; git commit -am \"Edit\"; git push origin post-update\r\n</code></pre>\n<p>Let’s check our post out.</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508360135Screenshot-2017-10-18-22.54.23.png\" alt=\"Final updated post\" /></p>\n<p>It works – deploying this script now is as simple as deploying the WP code of your app itself, and updating the webhook’s URL for the repo in question.</p>\n<h2 id=\"conclusion\">Conclusion</h2>\n<p>In true WordPress fashion, we hacked together a tool that took us less than an afternoon, but saved us days or weeks in the long run. The tool is now deployed and functioning adequately. There is, of course, room for updates. If you’re feeling inspired, try adding the following:</p>\n<ul>\n<li>modify the post updating procedure so that it uses <code>stdin</code> instead of a file, making it compatible with no-writable-filesystem hosts like AWS, Heroku, or Google Cloud.</li>\n<li>custom output types: instead of fixed <code>{:en}{:}{:hr}{:}</code>, maybe someone else is using a different multi-language plugin, or doesn’t use one at all. This should be customizable somehow.</li>\n<li>auto-insertion of images. Right now it’s manual, but the images are saved in the repo alongside the language versions and could probably be easily imported, auto-optimized, and added into the posts as well.</li>\n<li>staging mode – make sure the merged update first goes through to a staging version of the site before going to the main one, so the changes can be verified before being sent to master. Rather than having to activate and deactivate webhooks, why not make this programmable?</li>\n<li>a plugin interface: it would be handy to be able to define all this in the WP UI rather than in the code. A WP plugin abstraction around the functionality would, thus, be useful.</li>\n</ul>\n<p>With this tutorial, our intention was to show you that optimizing workflow isn’t such a big deal when you take the time to do it, and the return on investment for sacrificing some time on getting automation up and running can be immense when thinking long term.</p>\n<p>Any other ideas or tips on how to optimize this? Let us know!</p>\n","protected":false},"excerpt":{"rendered":"<p>At <a href=\"https://bitfalls.com\">Bitfalls.com</a>, we also use WordPress for now, and use the same peer review approach for content as we do <a href=\"https://www.sitepoint.com/write-for-us/\">at SitePoint</a>. </p>\n<p>We decided to build a tool which automatically pulls content from merged pull requests into articles, giving us the ability to fix typos and update posts from Github, and see the changes reflected on the live site. This tutorial will walk you through the creation of this tool, so you can start using it for your own WordPress site, or build your own version.</p>\n<h2 id=\"theplan\">The Plan</h2>\n<p>The first part is identifying the problem and the situation surrounding it.</p>\n<ul>\n<li>we use WPGlobus for multi-language support, which means content gets saved like this: <code>{:en}English content{:}{:hr}Croatian content{:}</code>.</li>\n<li>authors submit PRs via Github, the PRs are peer reviewed and merged, and then (currently) manually imported into WP’s Posts UI through the browser.</li>\n<li>every post has the same folder layout: <code>author_folder/post_folder/language/final.md</code></li>\n<li>this is slow and error prone, and sometimes mistakes slip by. It also makes updating posts tedious.</li>\n</ul>\n<p>The solution is the following:</p>\n<ul>\n<li>add a hook processor which will detect pushes to the master branch (i.e. merges from PRs)</li>\n<li>the processor should look for a meta file in the commit which would contain information on where to save the updated content</li>\n<li>the processor automatically converts the MD content to HTML, merges the languages in the WPGlobus format, and saves them into the database</li>\n</ul>\n<h2 id=\"bootstrapping\">Bootstrapping</h2>\n<p>If you’d like to follow along (highly recommended), please boot up a <a href=\"http://www.sitepoint.com/quick-tip-get-homestead-vagrant-vm-running/\">good virtual machine environment</a>, install the newest version of WordPress on it, and add the WPGlobus plugin. Alternatively, you can use a prepared WordPress box like <a href=\"https://www.sitepoint.com/wordpress-meets-vagrant-vvv/\">VVV</a>. Additionally, make sure your environment has <a href=\"https://www.sitepoint.com/use-ngrok-test-local-site/\">ngrok</a> installed – we’ll use that to pipe Github hook triggers to our local machine, so we can test locally instead of having to deploy.</p>\n<h2 id=\"hooks\">Hooks</h2>\n<p>For this experiment, let’s create a new repository. I’ll call mine <a href=\"https://github.com/Swader/autopush\">autopush</a>.</p>\n<p>In the settings of this repository, we need to add a <a href=\"https://github.com/Swader/autopush/settings/hooks/new\">new hook</a>. Since we’re talking about a temporary Ngrok URL, let’s first spin that up. In my case, entering the following on the host machine does the trick:</p>\n<pre><code class=\"bash language-bash\">ngrok http homestead.app:80\r\n</code></pre>\n<p>I was given the link <code>http://03672a64.ngrok.io</code>, so that’s what goes into the webhook, with an arbitrary suffix like <code>githook</code>. We only need push events. The <code>json</code> data type is cleaner, so that’s selected as a preference, and the final webhook setup looks something like this:</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508224690Screenshot-2017-10-17-09.17.48.png\" alt=\"Webhook setup\" /></p>\n<p>Let’s test this now.</p>\n<pre><code class=\"bash language-bash\">git clone https://github.com/swader/autopush\r\ncd autopush\r\ntouch README.md\r\necho \"This is a README file\" >> README.md\r\ngit add -A\r\ngit commit -am \"We're pushing for the first time\"\r\ngit push origin master\r\n</code></pre>\n<p>The ngrok log screen should display something like this:</p>\n<pre><code class=\"bash language-bash\">POST /githook/ 404 Not Found\r\n</code></pre>\n<p>This is fine. We haven’t made the <code>/githook</code> endpoint yet.</p>\n<h2 id=\"processingwebhooks\">Processing Webhooks</h2>\n<p>We’ll read this new data into WordPress with custom logic. Due to the spaghetti-code nature of WP itself, it’s easier to circumvent it entirely with a small custom application. First, we’ll create the <code>githook</code> folder in the WordPress project’s root, and an <code>index.php</code> file inside it. This makes the <code>/githook/</code> path accessible, and the hook will no longer return 404, but 200 OK.</p>\n<p>According to the <a href=\"https://developer.github.com/v3/activity/events/types/#pushevent\">docs</a>, the payload will have a <code>commits</code> field with a <code>modified</code> field in each commit. Since we’re only looking to update posts, not schedule them or delete them – those steps are still manual, for safety – we’ll only be paying attention to that one. Let’s see if we can catch it on a test push.</p>\n<p>First, we’ll save our request data to a text file, for debugging purposes. We can do this by modifying our <code>githook/index.php</code> file:</p>\n<pre><code class=\"php language-php\"><?php\r\nfile_put_contents('test.txt', file_get_contents('php://input'));\r\n</code></pre>\n<p>Then we’ll create a new branch, add a file, and push it online.</p>\n<pre><code class=\"bash language-bash\">git checkout -b test-branch\r\ntouch testfile.md\r\ngit add testfile.md\r\ngit commit -am \"Added test file\"\r\ngit push origin test-branch\r\n</code></pre>\n<p>Sure enough, our <code>test.json</code> file is filled with the payload now. <a href=\"http://jsoneditoronline.org/?id=3d65c7107d3233d8660ebb7419bf3104\">This</a> is the payload I got. You can see that we have only one commit, and that commit’s <code>modified</code> field is empty, while the <code>added</code> field has <code>testfile.md</code>. We can also see this happened on <code>refs/heads/test-branch</code>, ergo, we’re not interested in it. But what happens if we make a PR out of this branch and merge it?</p>\n","protected":false},"author":71392,"featured_media":154522,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[5903,4221,7888,402,37,6524],"tags":[3623,9805,5946,9770,2023,9760,310,8205],"_links":{"self":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/posts/160833"}],"collection":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/posts"}],"about":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/types/post"}],"author":[{"embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/users/71392"}],"replies":[{"embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/comments?post=160833"}],"version-history":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/posts/160833/revisions"}],"wp_featuredmedia":[{"embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/media/154522"}],"wp_attachment":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/media?parent=160833"}],"wp_term":[{"taxonomy":"category","embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/categories?post=160833"},{"taxonomy":"post_tag","embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/tags?post=160833"}],"curies":[{"name":"wp","href":"https://api.w.org/{rel}","templated":true}]}}
{"index":{"_index":"blogs","_id":160725,"_type":"default"}}
{"id":160725,"date":"2017-10-18T13:30:48","date_gmt":"2017-10-18T20:30:48","guid":{"rendered":"https://www.sitepoint.com/?p=160725"},"modified":"2017-10-19T23:50:32","modified_gmt":"2017-10-20T06:50:32","slug":"leave-your-competitors-in-the-dust-with-280-pre-built-websites","status":"publish","type":"post","link":"https://www.sitepoint.com/leave-your-competitors-in-the-dust-with-280-pre-built-websites/","title":{"rendered":"Leave Your Competitors in the Dust with 280+ Pre-Built Websites"},"content":{"rendered":"<p class=\"wp-special\"><em>This article was sponsored by <a href=\"http://themes.muffingroup.com/be/splash/?utm_source=sitepoint.com&utm_medium=content&utm_campaign=oct17\" rel=\"nofollow\">BeTheme</a>. Thank you for supporting the partners who make SitePoint possible.</em></p>\n<p>Are you a freelancer? Then your pay often depends on finding clients who can provide you with a steady stream of work. The competition can be fierce, however. Moreover, clients can be picky about who they feel can be trusted to deliver a quality product.</p>\n<p>Worrying about how other designers get lucrative assignments is a waste of time. It’s what you are doing to capture some of those assignments that counts, and it’s not as difficult as you might think.</p>\n<p>These three strategies can help you. They can put you on the path to getting more clients who are eager to pay you handsomely for your work.</p>\n<h2 id=\"1buildorupdateyourowncreativewebsite\">1. Build or Update Your Own Creative Website</h2>\n<p><a href=\"http://themes.muffingroup.com/be/webmaster/?utm_source=sitepoint.com&utm_medium=content&utm_campaign=oct17\"><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/15082188300.jpg\" alt=\"Be webmaster\" width=\"1000\" height=\"607\" class=\"aligncenter size-full wp-image-160729\" /></a></p>\n<p>Freelance web designers need to have their own websites to publicize their skills. Being able to present clients with a gallery or portfolio of your work is key to getting more work. Yet having a portfolio, even an awesome one, isn’t necessarily enough.</p>\n<p>You need to have your website’s visitors blown away by the user experience you’re able to provide. You want those prospective clients to see the features they would like to see in theirs. These include page load speed, SEO, navigation, and well-structured content.</p>\n<p>Now they know who can do it for them!</p>\n<h2 id=\"2gettingmoreclientsinlesstime\">2. Getting More Clients in Less Time</h2>\n<p>The strategy? It’s easier than you think. A problem you may face is that a range of clients represents a wide variety of industry niches. These also come with a variation of website types added into the mix.</p>\n<p>In addition, these clients can have vastly different website requirements. It’s incumbent on you to be nimble enough to find an appropriate template or theme quickly. You should be able to deliver a product in hours, instead of days or weeks.</p>\n<p>Do that, and you’re already a step or two ahead of the competition. Do it consistently, and before you know it, the competition will be the least of your concerns.</p>\n<p>Be Theme gives you the flexibility you need to completely satisfy any client’s needs, and do so quickly. <a href=\"http://themes.muffingroup.com/be/splash/?utm_source=sitepoint.com.com&utm_medium=content&utm_campaign=oct17\">Be Theme</a>’s pre-built websites address every single industry sector and business niche. It’s not all that difficult to create a beautiful website for a client the same day you get the go-ahead.</p>\n<p>These pre-built website examples demonstrate why this is possible.</p>\n<h3 id=\"showcasehttpthemesmuffingroupcombeshowcaseutm_sourcesitepointcomutm_mediumcontentutm_campaignoct17\"><a href=\"http://themes.muffingroup.com/be/showcase/?utm_source=sitepoint.com&utm_medium=content&utm_campaign=oct17\">Showcase</a></h3>\n<p><a href=\"http://themes.muffingroup.com/be/showcase/?utm_source=sitepoint.com&utm_medium=content&utm_campaign=oct17\"><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/15082188321.jpg\" alt=\"Showcase\" width=\"1000\" height=\"563\" class=\"aligncenter size-large wp-image-160730\" /></a></p>\n<p>This is an excellent example for a creative client with a product or service to sell. You might even consider it as a starting point for your own creative website.</p>\n<h3 id=\"adagencyhttpthemesmuffingroupcombeadagencyutm_sourcesitepointcomutm_mediumcontentutm_campaignoct17\"><a href=\"http://themes.muffingroup.com/be/adagency/?utm_source=sitepoint.com&utm_medium=content&utm_campaign=oct17\">AdAgency</a></h3>\n<p><a href=\"http://themes.muffingroup.com/be/adagency/?utm_source=sitepoint.com&utm_medium=content&utm_campaign=oct17\"><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/15082188352.jpg\" alt=\"AdAgency\" width=\"1000\" height=\"537\" class=\"aligncenter size-large wp-image-160731\" /></a></p>\n<p>Here’s a perfect fit for an ad or marketing agency.</p>\n<h3 id=\"videohttpthemesmuffingroupcombevideoutm_sourcesitepointcomutm_mediumcontentutm_campaignoct17\"><a href=\"http://themes.muffingroup.com/be/video/?utm_source=sitepoint.com&utm_medium=content&utm_campaign=oct17\">Video</a></h3>\n<p><a href=\"http://themes.muffingroup.com/be/video/?utm_source=sitepoint.com&utm_medium=content&utm_campaign=oct17\"><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/15082188383.jpg\" alt=\"Video\" width=\"1000\" height=\"537\" class=\"aligncenter size-large wp-image-160732\" /></a></p>\n<p>A creative layout for a video production agency.</p>\n<h3 id=\"modelhttpthemesmuffingroupcombemodelutm_sourcesitepointcomutm_mediumcontentutm_campaignoct17\"><a href=\"http://themes.muffingroup.com/be/model/?utm_source=sitepoint.com&utm_medium=content&utm_campaign=oct17\">Model</a></h3>\n<p><a href=\"http://themes.muffingroup.com/be/model/?utm_source=sitepoint.com&utm_medium=content&utm_campaign=oct17\"><br />\n<img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/15082188404.jpg\" alt=\"Model\" width=\"1000\" height=\"563\" class=\"aligncenter size-large wp-image-160733\" /></a></p>\n<p>A good choice for a modeling agency, a fashion designer, or even a photographer.</p>\n<h3 id=\"barberhttpthemesmuffingroupcombebarberutm_sourcesitepointcomutm_mediumcontentutm_campaignoct17\"><a href=\"http://themes.muffingroup.com/be/barber/?utm_source=sitepoint.com&utm_medium=content&utm_campaign=oct17\">Barber</a></h3>\n<p><a href=\"http://themes.muffingroup.com/be/barber/?utm_source=sitepoint.com&utm_medium=content&utm_campaign=oct17\"><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/15082188435.jpg\" alt=\"Barber\" width=\"1000\" height=\"537\" class=\"aligncenter size-large wp-image-160734\" /></a></p>\n<p>For beauty salons, barbers, and visual artists.</p>\n<h3 id=\"designhttpthemesmuffingroupcombedesignutm_sourcesitepointcomutm_mediumcontentutm_campaignoct17\"><a href=\"http://themes.muffingroup.com/be/design/?utm_source=sitepoint.com&utm_medium=content&utm_campaign=oct17\">Design</a></h3>\n<p><a href=\"http://themes.muffingroup.com/be/design/?utm_source=sitepoint.com&utm_medium=content&utm_campaign=oct17\"><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/15082188486.jpg\" alt=\"Design\" width=\"1000\" height=\"563\" class=\"aligncenter size-large wp-image-160735\" /></a></p>\n<p>This will be a good fit for a web design agency. It will also serve bloggers well.</p>\n<p>None of the above examples would seem, at a glance, to have much in common — at least in terms of their layouts.</p>\n<p>They do have several things in common, however.</p>\n<p>They all feature interactive galleries and each pre-built website is completely customizable. In addition, the high-quality imagery is the norm and navigation is easy. Moreover, a significant amount of emphasis is placed on the client’s brand.</p>\n<h2 id=\"30onepagewebsites\">30+ One-Page Websites</h2>\n<p>One-pagers can be challenging since clients’ requirements tend to be unique. These are often a matter of personal taste. Be Themes’ large selection of one-page pre-built websites is perfect just for that. It gives you the material you need to please the most demanding clients.</p>\n<h3 id=\"landingpagehttpthemesmuffingroupcombelandingutm_sourcesitepointcomutm_mediumcontentutm_campaignoct17\"><a href=\"http://themes.muffingroup.com/be/landing/?utm_source=sitepoint.com&utm_medium=content&utm_campaign=oct17\">Landing Page</a></h3>\n<p><a href=\"http://themes.muffingroup.com/be/landing/?utm_source=sitepoint.com&utm_medium=content&utm_campaign=oct17\"><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/15082188517.jpg\" alt=\"Landing Page\" width=\"1000\" height=\"537\" class=\"aligncenter size-large wp-image-160736\" /></a></p>\n<h3 id=\"parallaxhttpthemesmuffingroupcombeparallaxutm_sourcesitepointcomutm_mediumcontentutm_campaignoct17\"><a href=\"http://themes.muffingroup.com/be/parallax/?utm_source=sitepoint.com&utm_medium=content&utm_campaign=oct17\">Parallax</a></h3>\n<p><a href=\"http://themes.muffingroup.com/be/parallax/?utm_source=sitepoint.com&utm_medium=content&utm_campaign=oct17\"><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/15082188548.jpg\" alt=\"Parallax\" width=\"1000\" height=\"537\" class=\"aligncenter size-large wp-image-160737\" /></a></p>\n<h3 id=\"servicehttpthemesmuffingroupcombeserviceutm_sourcesitepointcomutm_mediumcontentutm_campaignoct17\"><a href=\"http://themes.muffingroup.com/be/service/?utm_source=sitepoint.com&utm_medium=content&utm_campaign=oct17\">Service</a></h3>\n<p><a href=\"http://themes.muffingroup.com/be/service/?utm_source=sitepoint.com&utm_medium=content&utm_campaign=oct17\"><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/15082188579.jpg\" alt=\"Service\" width=\"1000\" height=\"537\" class=\"aligncenter size-large wp-image-160738\" /></a></p>\n<h3 id=\"ebookhttpthemesmuffingroupcombeebookutm_sourcesitepointcomutm_mediumcontentutm_campaignoct17\"><a href=\"http://themes.muffingroup.com/be/ebook/?utm_source=sitepoint.com&utm_medium=content&utm_campaign=oct17\">Ebook</a></h3>\n<p><a href=\"http://themes.muffingroup.com/be/ebook/?utm_source=sitepoint.com&utm_medium=content&utm_campaign=oct17\"><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/150821885910.jpg\" alt=\"Ebook\" width=\"1000\" height=\"537\" class=\"aligncenter size-large wp-image-160739\" /></a></p>\n<p>These one-page pre-built websites are fully responsive. Also, they feature a clever use of white space and their content can be arranged in any way you or your client want.</p>\n<p>This is true for all 280+ pre-built websites in Be Theme’s collection.</p>\n<h2 id=\"9prebuiltwebsitesforonlineshops\">9+ Pre-built Websites for Online Shops</h2>\n<p>Designed with eCommerce in mind, these pre-built websites integrate perfectly with Shopify.</p>\n<h3 id=\"shoeshttpthemesmuffingroupcombeshoesutm_sourcesitepointcomutm_mediumcontentutm_campaignoct17\"><a href=\"http://themes.muffingroup.com/be/shoes/?utm_source=sitepoint.com&utm_medium=content&utm_campaign=oct17\">Shoes</a></h3>\n<p><a href=\"http://themes.muffingroup.com/be/shoes/?utm_source=sitepoint.com&utm_medium=content&utm_campaign=oct17\"><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/150821886211.jpg\" alt=\"Shoes\" width=\"1000\" height=\"537\" class=\"aligncenter size-large wp-image-160740\" /></a></p>\n<h3 id=\"storehttpthemesmuffingroupcombestoreutm_sourcesitepointcomutm_mediumcontentutm_campaignoct17\"><a href=\"http://themes.muffingroup.com/be/store/?utm_source=sitepoint.com&utm_medium=content&utm_campaign=oct17\">Store</a></h3>\n<p><a href=\"http://themes.muffingroup.com/be/store/?utm_source=sitepoint.com&utm_medium=content&utm_campaign=oct17\"><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/150821886612.jpg\" alt=\"Store\" width=\"1000\" height=\"537\" class=\"aligncenter size-large wp-image-160741\" /></a></p>\n<h3 id=\"shophttpthemesmuffingroupcombeshoputm_sourcesitepointcomutm_mediumcontentutm_campaignoct17\"><a href=\"http://themes.muffingroup.com/be/shop/?utm_source=sitepoint.com&utm_medium=content&utm_campaign=oct17\">Shop</a></h3>\n<p><a href=\"http://themes.muffingroup.com/be/shop/?utm_source=sitepoint.com&utm_medium=content&utm_campaign=oct17\"><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/150821886913.jpg\" alt=\"Shop\" width=\"1000\" height=\"537\" class=\"aligncenter size-large wp-image-160742\" /></a></p>\n<h3 id=\"cosmeticshttpthemesmuffingroupcombecosmeticsutm_sourcesitepointcomutm_mediumcontentutm_campaignoct17\"><a href=\"http://themes.muffingroup.com/be/cosmetics/?utm_source=sitepoint.com&utm_medium=content&utm_campaign=oct17\">Cosmetics</a></h3>\n<p><a href=\"http://themes.muffingroup.com/be/cosmetics/?utm_source=sitepoint.com&utm_medium=content&utm_campaign=oct17\"><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/150821887214.jpg\" alt=\"Cosmetics\" width=\"1000\" height=\"537\" class=\"aligncenter size-large wp-image-160743\" /></a></p>\n<p>Each of the 9+ pre-built websites feature customizable galleries. They have easy to use menus, and order forms that are no-brainers to fill out. In each case, the designs are structured to showcase a client’s products.</p>\n<h2 id=\"prebuiltsitesforspecificniches\">Pre-built Sites for Specific Niches</h2>\n<p>You’ll also have your share of sites for specific niches to work with, including…</p>\n<h3 id=\"herbalhttpthemesmuffingroupcombeherbalutm_sourcesitepointcomutm_mediumcontentutm_campaignoct17\"><a href=\"http://themes.muffingroup.com/be/herbal/?utm_source=sitepoint.com&utm_medium=content&utm_campaign=oct17\">Herbal</a></h3>\n<p><a href=\"http://themes.muffingroup.com/be/herbal/?utm_source=sitepoint.com&utm_medium=content&utm_campaign=oct17\"><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/150821887615.jpg\" alt=\"Herbal\" width=\"1000\" height=\"562\" class=\"aligncenter size-large wp-image-160744\" /></a></p>\n<p>20+ pre-built websites for health & wellness.</p>\n<h3 id=\"sportsclubhttpthemesmuffingroupcombesportsclubutm_sourcesitepointcomutm_mediumcontentutm_campaignoct17\"><a href=\"http://themes.muffingroup.com/be/sportsclub/?utm_source=sitepoint.com&utm_medium=content&utm_campaign=oct17\">Sportsclub</a></h3>\n<p><a href=\"http://themes.muffingroup.com/be/sportsclub/?utm_source=sitepoint.com&utm_medium=content&utm_campaign=oct17\"><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/150821887916.jpg\" alt=\"Sportsclub\" width=\"1000\" height=\"537\" class=\"aligncenter size-large wp-image-160745\" /></a></p>\n<p>12+ for the growing fitness & nutrition industry.</p>\n<h3 id=\"clubhttpthemesmuffingroupcombeclubutm_sourcesitepointcomutm_mediumcontentutm_campaignoct17\"><a href=\"http://themes.muffingroup.com/be/club/?utm_source=sitepoint.com&utm_medium=content&utm_campaign=oct17\">Club</a></h3>\n<p><a href=\"http://themes.muffingroup.com/be/club/?utm_source=sitepoint.com&utm_medium=content&utm_campaign=oct17\"><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/150821888217.jpg\" alt=\"Club\" width=\"1000\" height=\"537\" class=\"aligncenter size-large wp-image-160746\" /></a></p>\n<p>16+ for businesses and agencies promoting events & nightlife.</p>\n<h3 id=\"bistrohttpthemesmuffingroupcombebistroutm_sourcesitepointcomutm_mediumcontentutm_campaignoct17\"><a href=\"http://themes.muffingroup.com/be/bistro/?utm_source=sitepoint.com&utm_medium=content&utm_campaign=oct17\">Bistro</a></h3>\n<p><a href=\"http://themes.muffingroup.com/be/bistro/?utm_source=sitepoint.com&utm_medium=content&utm_campaign=oct17\"><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/150821888618.jpg\" alt=\"Bistro\" width=\"1000\" height=\"537\" class=\"aligncenter size-large wp-image-160747\" /></a></p>\n<p>9+ for restaurants, bars, bistros, cafes, and diners.</p>\n<h3 id=\"codehttpthemesmuffingroupcombecodeutm_sourcesitepointcomutm_mediumcontentutm_campaignoct17\"><a href=\"http://themes.muffingroup.com/be/code/?utm_source=sitepoint.com&utm_medium=content&utm_campaign=oct17\">Code</a></h3>\n<p><a href=\"http://themes.muffingroup.com/be/code/?utm_source=sitepoint.com&utm_medium=content&utm_campaign=oct17\"><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/150821888919.jpg\" alt=\"Code\" width=\"1000\" height=\"537\" class=\"aligncenter size-large wp-image-160748\" /></a></p>\n<p>10+ for the super-charged, fast-growing IT services and products sector.</p>\n<h3 id=\"accountanthttpthemesmuffingroupcombeaccountantutm_sourcesitepointcomutm_mediumcontentutm_campaignoct17\"><a href=\"http://themes.muffingroup.com/be/accountant/?utm_source=sitepoint.com&utm_medium=content&utm_campaign=oct17\">Accountant</a></h3>\n<p><a href=\"http://themes.muffingroup.com/be/accountant/?utm_source=sitepoint.com&utm_medium=content&utm_campaign=oct17\"><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/150821889220.jpg\" alt=\"Accountant\" width=\"1000\" height=\"537\" class=\"aligncenter size-large wp-image-160749\" /></a></p>\n<p>And 7+ to make finance- and bookkeeping-oriented businesses sound more exciting.</p>\n<p>Plus many more industries and niches, if you care to browse through the entire selection!</p>\n<h2 id=\"3letyourcompetitorscontinuetowasteprecioustime\">3. Let Your Competitors Continue to Waste Precious Time</h2>\n<p>It’s what you’ve stopped doing, and what much of the competition will continue to do. It also will put you ahead of the pack with respect to finding new clients. </p>\n<p>You don’t ever want to make a client wait. When you do, the message you’re sending is that your client isn’t that important. He/she thinks that they are relatively low on your list of priorities.</p>\n<p>You want to strive to send exactly the opposite message. One that says you care about your client enough to make him or her your #1 priority. With some assistance from Be Theme, you’ll have no problem reducing the hours of search time to a few minutes. You will be able to amaze your clients with same-day turnaround!</p>\n<h2 id=\"conclusion\">Conclusion</h2>\n<p>Moving ahead of the competition is a three-step process. The order isn’t critical, so long as you start today, and complete each step as quickly as possible.</p>\n<p>Build your own creative website to showcase your skills, and continue to improve on it!</p>\n<p>Add each successful job to your portfolio. In time, you’ll see an uptick in the number of clients seeking your services. Some of your best customers are repeat customers and referred customers.</p>\n<p>Never let a client wait! You can rely on <a href=\"http://themes.muffingroup.com/be/splash/?utm_source=sitepoint.com.com&utm_medium=content&utm_campaign=oct17\">Be Theme</a>’s 280+ themes to help you deliver high-quality products in record time.</p>\n","protected":false},"excerpt":{"rendered":"<p class=\"wp-special\"><em>This article was sponsored by <a href=\"http://themes.muffingroup.com/be/splash/?utm_source=sitepoint.com&utm_medium=content&utm_campaign=oct17\" rel=\"nofollow\">Be Themes</a>. Thank you for supporting the partners who make SitePoint possible.</em></p>\n<p>Are you a freelancer? Then your pay often depends on finding clients who can provide you with a steady stream of work. The competition can be fierce, however. Moreover, clients can be picky about who they feel can be trusted to deliver a quality product.</p>\n<p>Worrying about how other designers get lucrative assignments is a waste of time. It’s what you are doing to capture some of those assignments that counts, and it’s not as difficult as you might think.</p>\n<p>These three strategies can help you. They can put you on the path to getting more clients who are eager to pay you handsomely for your work.</p>\n<h2 id=\"1buildorupdateyourowncreativewebsite\">1. Build or Update Your Own Creative Website</h2>\n<p><a href=\"http://themes.muffingroup.com/be/webmaster/?utm_source=sitepoint.com&utm_medium=content&utm_campaign=oct17\"><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/15082188300.jpg\" alt=\"Be webmaster\" width=\"1000\" height=\"607\" class=\"aligncenter size-full wp-image-160729\" /></a></p>\n<p>Freelance web designers need to have their own websites to publicize their skills. Being able to present clients with a gallery or portfolio of your work is key to getting more work. Yet having a portfolio, even an awesome one, isn’t necessarily enough.</p>\n<p>You need to have your website’s visitors blown away by the user experience you’re able to provide. You want those prospective clients to see the features they would like to see in theirs. These include page load speed, SEO, navigation, and well-structured content.</p>\n<p>Now they know who can do it for them!</p>\n<h2 id=\"2gettingmoreclientsinlesstime\">2. Getting More Clients in Less Time</h2>\n<p>The strategy? It’s easier than you think. A problem you may face is that a range of clients represents a wide variety of industry niches. These also come with a variation of website types added into the mix.</p>\n<p>In addition, these clients can have vastly different website requirements. It’s incumbent on you to be nimble enough to find an appropriate template or theme quickly. You should be able to deliver a product in hours, instead of days or weeks.</p>\n<p>Do that, and you’re already a step or two ahead of the competition. Do it consistently, and before you know it, the competition will be the least of your concerns.</p>\n<p>Be Theme gives you the flexibility you need to completely satisfy any client’s needs, and do so quickly. <a href=\"http://themes.muffingroup.com/be/splash/?utm_source=sitepoint.com.com&utm_medium=content&utm_campaign=oct17\">Be Theme</a>’s pre-built websites address every single industry sector and business niche. It’s not all that difficult to create a beautiful website for a client the same day you get the go-ahead.</p>\n<p>These pre-built website examples demonstrate why this is possible.</p>\n<h3 id=\"showcasehttpthemesmuffingroupcombeshowcaseutm_sourcesitepointcomutm_mediumcontentutm_campaignoct17\"><a href=\"http://themes.muffingroup.com/be/showcase/?utm_source=sitepoint.com&utm_medium=content&utm_campaign=oct17\">Showcase</a></h3>\n<p><a href=\"http://themes.muffingroup.com/be/showcase/?utm_source=sitepoint.com&utm_medium=content&utm_campaign=oct17\"><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/15082188321.jpg\" alt=\"Showcase\" width=\"1000\" height=\"563\" class=\"aligncenter size-large wp-image-160730\" /></a></p>\n<p>This is an excellent example for a creative client with a product or service to sell. You might even consider it as a starting point for your own creative website.</p>\n","protected":false},"author":72596,"featured_media":160751,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[5856,5849],"tags":[11580,9553,6298,310,6522],"_links":{"self":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/posts/160725"}],"collection":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/posts"}],"about":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/types/post"}],"author":[{"embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/users/72596"}],"replies":[{"embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/comments?post=160725"}],"version-history":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/posts/160725/revisions"}],"wp_featuredmedia":[{"embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/media/160751"}],"wp_attachment":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/media?parent=160725"}],"wp_term":[{"taxonomy":"category","embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/categories?post=160725"},{"taxonomy":"post_tag","embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/tags?post=160725"}],"curies":[{"name":"wp","href":"https://api.w.org/{rel}","templated":true}]}}
{"index":{"_index":"blogs","_id":160771,"_type":"default"}}
{"id":160771,"date":"2017-10-18T09:00:13","date_gmt":"2017-10-18T16:00:13","guid":{"rendered":"https://www.sitepoint.com/?p=160771"},"modified":"2017-10-19T17:00:33","modified_gmt":"2017-10-20T00:00:33","slug":"learning-angular-everything-you-need-to-get-started","status":"publish","type":"post","link":"https://www.sitepoint.com/learning-angular-everything-you-need-to-get-started/","title":{"rendered":"Learning Angular: Everything You Need to Get Started"},"content":{"rendered":"<p>Whether it’s AngularJS 1.X – a framework, or Angular – a platform, Google’s Angular project has taken over the web. Here’s a collection of articles, projects and courses that’ll help you get to grips with the powerful front-end tool.</p>\n<p>But if you’re starting from scratch, and you’d like to go from zero to expert fast, a course recommendation. For expert-led online Angular training courses you can’t go past Ultimate Angular by Todd Motto. <a href=\"https://ultimateangular.com/\">Try his courses here</a>, and use the code <strong>SITEPOINT</strong> to get <strong>25% off</strong> and to help support SitePoint.</p>\n<h2 id=\"introductionsandcomparisons\">Introductions and Comparisons</h2>\n<ul>\n<li>Angular version naming got a little complicated this year, <a href=\"http://angularjs.blogspot.com.au/2017/01/branding-guidelines-for-angular-and.html\">here are the official naming conventions for specific versions of the platform</a> [angularjs], which we’ve tried to follow here and elsewhere on the site.</li>\n<li><a href=\"https://www.sitepoint.com/react-vs-angular/\">How to decide between React and Angular</a> [sitepoint].</li>\n</ul>\n<h2 id=\"fundamentals\">Fundamentals</h2>\n<ul>\n<li><a href=\"https://www.sitepoint.com/angularjs-wordpress-rest-api/\">How to create a single-page app with AngularJS and the WordPress REST API</a> [sitepoint].</li>\n<li><a href=\"https://www.sitepoint.com/managing-state-angular-2-ngrx/\">A guide to managing state in Angular apps with ngrx/store</a> [sitepoint].</li>\n<li><a href=\"https://blog.nrwl.io/managing-state-in-angular-applications-22b75ef5625f\">Managing state in Angular apps</a> [blog.nrwl].</li>\n<li><a href=\"https://www.sitepoint.com/persisting-state-in-angularjs/\">Persisting state in AngularJS</a> [sitepoint].</li>\n<li><a href=\"https://x-team.com/blog/angular-typescript/\">Getting intimate with Angular and TypeScript</a> [x-team].</li>\n<li><a href=\"https://medium.com/curated-by-versett/building-maintainable-angular-2-applications-5b9ec4b463a1\">How to build maintainable Angular apps</a> [medium/curated-by-versett].</li>\n<li><a href=\"https://www.sitepoint.com/angular-2-mockbackend/\">How to develop apps with Angular mockbackend</a> [sitepoint].</li>\n<li><a href=\"https://github.com/mgechev/angularjs-style-guide\">A community-drive collection of best practices and style guidelines for AngularJS</a> [github/mgechev].</li>\n</ul>\n<h3 id=\"testing\">Testing</h3>\n<ul>\n<li><a href=\"http://corinnekrych.blogspot.com.au/2017/05/testing-your-services-with-angular.html\">A guide to testing your services with Angular</a> [corinnekrych.blogspot].</li>\n<li><a href=\"http://corinnekrych.blogspot.com.au/2017/05/test-your-angular-component.html\">How to test your Angular component</a> [corinnekrych.blogspot].</li>\n</ul>\n<h3 id=\"authentication\">Authentication</h3>\n<ul>\n<li><a href=\"http://angularjs.blogspot.com.au/2016/11/easy-angular-authentication-with-json.html\">Angular authentication with JSON</a> [angularjs.blogspot].</li>\n<li><a href=\"https://www.sitepoint.com/easy-angularjs-authentication-with-auth0/\">And easy Angular authentication with Auth0</a> [sitepoint].</li>\n</ul>\n<h2 id=\"slightlymoreadvanced\">Slightly More Advanced</h2>\n<ul>\n<li><a href=\"https://www.sitepoint.com/productivity-tips-for-webstorm-and-angular-part-1/\">Productivity tips for Angular and WebStorm</a> [sitepoint].</li>\n<li><a href=\"https://www.sitepoint.com/mean-stack-angular-2-angular-cli/\">Developing an app with Angular 2+ and the Angular CLI</a> [sitepoint].</li>\n<li><a href=\"https://medium.com/@bojzi/anatomy-of-a-large-angular-application-f098e5e36994\">An anatomy of a large Angular application</a> [medium].</li>\n<li><a href=\"https://medium.com/@ahsan.ayaz/creating-progressive-web-apps-with-angular-part-1-8f752b866f29\">Creating Progressive Web Apps with Angular</a> [medium].</li>\n<li><a href=\"https://blog.upstate.agency/improving-angular-performance-with-1-line-of-code-a1fb814a6476\">Improving Angular performance with one line of code</a> [blog.upstate].</li>\n<li><a href=\"https://medium.com/dailyjs/building-angular-apps-at-scale-813ef42add04\">Building Angular apps at scale</a> [medium].</li>\n<li><a href=\"https://www.thepolyglotdeveloper.com/2017/03/device-geolocation-nativescript-angular-application/\">Track device geolocation in NativeScript Angular mobile applications</a> [thepolyglotdeveloper].</li>\n<li><a href=\"https://www.sitepoint.com/deploy-rest-api-in-30-mins-mlab-heroku/\">Deploy your own REST API using mLab and Heroku</a> [sitepoint].</li>\n</ul>\n<h2 id=\"courses\">Courses</h2>\n<p>If cobbling together your own learning path via articles isn’t for you, or you’d like to make sure you’re across all the concepts and techniques, these are the structured Angular courses we recommend.</p>\n<ul>\n<li><a href=\"https://ultimateangular.com/\">Ultimate Angular</a> [ultimateangular] is the gold standard in Angular education, from Angular tutor extraordinaire Todd Motto. Use coupon code <strong>‘SITEPOINT’</strong> at checkout to get <strong>25% off</strong> and help support SitePoint.</li>\n</ul>\n<h2 id=\"projects\">Projects</h2>\n<p>You’ve got the basics – and perhaps even a little bit more. Here are some projects to take on to put that knowledge into practice.</p>\n<p>First things first: a very popular and well-regarded series of articles on SitePoint, covering how to write a todo app in Angular 2:</p>\n<ul>\n<li>Part 0 — <a href=\"https://www.sitepoint.com/ultimate-angular-cli-reference/\">The Ultimate Angular CLI Reference Guide</a></li>\n<li>Part 1 — <a href=\"https://www.sitepoint.com/angular-2-tutorial/\">Getting our first version of the Todo application up and running</a></li>\n<li>Part 2 — <a href=\"https://www.sitepoint.com/understanding-component-architecture-angular/\">Creating separate components to display a list of todo’s and a single todo</a></li>\n<li>Part 3 — <a href=\"https://www.sitepoint.com/angular-rxjs-create-api-service-rest-backend/\">Update the Todo service to communicate with a REST API</a></li>\n<li>Part 4 — <a href=\"https://www.sitepoint.com/component-routing-angular-router/\">Use Angular router to resolve data</a>.</li>\n</ul>\n<ul>\n<li>Then, <a href=\"https://www.sitepoint.com/planning-mean-stack-application/\">a practical guide to planning a MEAN stack app</a> [sitepoint].</li>\n<li><a href=\"https://x-team.com/blog/twitter-clone-angular-architecture/\">Building a Twitter clone with Angular (part 1)</a> [x-team].</li>\n<li><a href=\"https://toddmotto.com/building-tesla-range-calculator-angular-2-reactive-forms\">Building a Tesla battery range calculator with Angular 2 and reactive forms</a> [toddmotto].</li>\n<li><a href=\"https://www.sitepoint.com/chrome-extension-angular-2/\">How to build a Chrome extension in Angular 2</a> [sitepoint].</li>\n<li><a href=\"https://developer.telerik.com/products/kendo-ui/create-style-angular-app-kendo-ui/\">How to create an Angular app and style it with Kendo UI</a> [developer.telerik].</li>\n<li><a href=\"https://www.sitepoint.com/chart-component-angular2-fusioncharts/\">Building a chart component with Angular 2 and FusionCharts</a> [sitepoint].</li>\n</ul>\n","protected":false},"excerpt":{"rendered":"<p>Whether it’s AngularJS 1.X – a framework, or Angular – a platform, Google’s Angular project has taken over the web. Here’s a collection of articles, projects and courses that’ll help you get to grips with the powerful front-end tool.</p>\n<p>But if you’re starting from scratch, and you’d like to go from zero to expert fast, a course recommendation. For expert-led online Angular training courses you can’t go past Ultimate Angular by Todd Motto. Try his courses <a href=\"https://ultimateangular.com/\">here</a> [ultimateangular], and use the code SITEPOINT to get 25% off and to help support SitePoint.</p>\n<h2 id=\"introductionsandcomparisons\">Introductions and Comparisons</h2>\n<ul>\n<li>Angular version naming got a little complicated this year, <a href=\"http://angularjs.blogspot.com.au/2017/01/branding-guidelines-for-angular-and.html\">here are the official naming conventions for specific versions of the platform</a> [angularjs], which we’ve tried to follow here and elsewhere on the site.</li>\n<li><a href=\"https://www.sitepoint.com/react-vs-angular/\">How to decide between React and Angular</a> [sitepoint].</li>\n</ul>\n<h2 id=\"fundamentals\">Fundamentals</h2>\n<ul>\n<li><a href=\"https://www.sitepoint.com/angularjs-wordpress-rest-api/\">How to create a single-page app with AngularJS and the WordPress REST API</a> [sitepoint].</li>\n<li><a href=\"https://www.sitepoint.com/managing-state-angular-2-ngrx/\">A guide to managing state in Angular apps with ngrx/store</a> [sitepoint].</li>\n<li><a href=\"https://blog.nrwl.io/managing-state-in-angular-applications-22b75ef5625f\">Managing state in Angular apps</a> [blog.nrwl].</li>\n<li><a href=\"https://www.sitepoint.com/persisting-state-in-angularjs/\">Persisting state in AngularJS</a> [sitepoint].</li>\n<li><a href=\"https://medium.com/curated-by-versett/building-maintainable-angular-2-applications-5b9ec4b463a1\">How to build maintainable Angular apps</a> [medium/curated-by-versett].</li>\n<li><a href=\"https://www.sitepoint.com/angular-2-mockbackend/\">How to develop apps with Angular mockbackend</a> [sitepoint].</li>\n<li><a href=\"https://github.com/mgechev/angularjs-style-guide\">A community-drive collection of best practices and style guidelines for AngularJS</a> [github/mgechev].</li>\n</ul>\n<h3 id=\"testing\">Testing</h3>\n<ul>\n<li><a href=\"http://corinnekrych.blogspot.com.au/2017/05/testing-your-services-with-angular.html\">A guide to testing your services with Angular</a> [corinnekrych.blogspot].</li>\n<li><a href=\"http://corinnekrych.blogspot.com.au/2017/05/test-your-angular-component.html\">How to test your Angular component</a> [corinnekrych.blogspot].</li>\n</ul>\n<h3 id=\"authentication\">Authentication</h3>\n<ul>\n<li><a href=\"http://angularjs.blogspot.com.au/2016/11/easy-angular-authentication-with-json.html\">Angular authentication with JSON</a> [angularjs.blogspot].</li>\n<li><a href=\"https://www.sitepoint.com/easy-angularjs-authentication-with-auth0/\">And easy Angular authentication with Auth0</a> [sitepoint].</li>\n</ul>\n<h2 id=\"slightlymoreadvanced\">Slightly More Advanced</h2>\n<ul>\n<li><a href=\"https://www.sitepoint.com/mean-stack-angular-2-angular-cli/\">Developing an app with Angular 2+ and the Angular CLI</a> [sitepoint] </li>\n<li><a href=\"https://medium.com/@bojzi/anatomy-of-a-large-angular-application-f098e5e36994\">An anatomy of a large Angular application</a> [medium]</li>\n<li><a href=\"https://medium.com/@ahsan.ayaz/creating-progressive-web-apps-with-angular-part-1-8f752b866f29\">Creating Progressive Web Apps with Angular</a> [medium]</li>\n<li><a href=\"https://blog.upstate.agency/improving-angular-performance-with-1-line-of-code-a1fb814a6476\">Improving Angular performance with one line of code</a> [blog.upstate]</li>\n<li><a href=\"https://medium.com/dailyjs/building-angular-apps-at-scale-813ef42add04\">Building Angular apps at scale</a> [medium]</li>\n<li><a href=\"https://www.thepolyglotdeveloper.com/2017/03/device-geolocation-nativescript-angular-application/\">Track device geolocation in NativeScript Angular mobile applications</a> [thepolyglotdeveloper]</li>\n<li><a href=\"https://www.sitepoint.com/deploy-rest-api-in-30-mins-mlab-heroku/\">Deploy your own REST API using mLab and Heroku</a> [sitepoint]</li>\n</ul>\n<h2 id=\"projects\">Projects</h2>\n<p>You’ve got the basics – and perhaps even a little bit more. Here are some projects to take on to put that knowledge into practice.</p>\n","protected":false},"author":71721,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[768,407],"tags":[6152,8530,9553,1900],"_links":{"self":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/posts/160771"}],"collection":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/posts"}],"about":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/types/post"}],"author":[{"embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/users/71721"}],"replies":[{"embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/comments?post=160771"}],"version-history":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/posts/160771/revisions"}],"wp_attachment":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/media?parent=160771"}],"wp_term":[{"taxonomy":"category","embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/categories?post=160771"},{"taxonomy":"post_tag","embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/tags?post=160771"}],"curies":[{"name":"wp","href":"https://api.w.org/{rel}","templated":true}]}}
{"index":{"_index":"blogs","_id":160604,"_type":"default"}}
{"id":160604,"date":"2017-10-16T13:00:45","date_gmt":"2017-10-16T20:00:45","guid":{"rendered":"https://www.sitepoint.com/?p=160604"},"modified":"2017-10-13T06:19:40","modified_gmt":"2017-10-13T13:19:40","slug":"ember-js-perfect-framework-web-applications","status":"publish","type":"post","link":"https://www.sitepoint.com/ember-js-perfect-framework-web-applications/","title":{"rendered":"Ember.js: The Perfect Framework for Web Applications"},"content":{"rendered":"<p class=\"wp-special\">Ember.js is an opinionated frontend JavaScript framework that has been getting a lot of interest lately. This article will introduce some key concepts of the framework while building a simple application with it, in order to show a basic example of what it is capable of producing.</p>\n\n<p>Our example application is going to be a Dice Roller, including the ability to roll some dice and view a history of all dice rolls that have been performed to date. A fully working version of this application is available from <a href=\"https://github.com/sazzer/dice-roller\">Github</a></p>\n<p>The Ember.js framework pulls together a lot of modern JavaScript concepts and technologies into one single bundle, including but not limited to:</p>\n<ul>\n<li>The use of the <a href=\"https://babeljs.io/\">Babel</a> transpiler tool, to support ES2016 throughout.</li>\n<li>Testing support at the Unit, Integration and Acceptance levels as standard, powered by <a href=\"https://github.com/testem/testem\">Testem</a> and <a href=\"https://qunitjs.com/\">QTest</a>.</li>\n<li>Asset building using <a href=\"http://broccolijs.com/\">Broccoli.js</a>.</li>\n<li>Support for live reloading, for shorter development cycle times.</li>\n<li>Templating using the <a href=\"http://handlebarsjs.com/\">Handlebars</a> markup syntax.</li>\n<li>URL Routing first development to ensure that deep linking is fully supported throughout.</li>\n<li>Full data layer built around <a href=\"http://jsonapi.org/\">JSON API</a>, but pluggable for whatever API access you need.</li>\n</ul>\n<p>In order to work with Ember.js, it is assumed that you have an up-to-date installation of Node.js and npm. If not then these can be downloaded and installed from the <a href=\"https://nodejs.org/\">Node.js website</a>.</p>\n<p>It should also be mentioned that Ember is purely a frontend framework. It has a number of ways of interacting with the backend of your choice, but this backend is not in any way handled by Ember itself. </p>\n<h2 id=\"introducingembercli\">Introducing ember-cli</h2>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2015/03/1425997476emberjs-logo-300x300.png\" alt=\"Ember.js logo\" width=\"300\" height=\"300\" class=\"alignright size-medium wp-image-101094\" /></p>\n<p>A lot of the power of Ember.js comes from its command line interface (CLI). This tool – known as ember-cli – powers much of the development lifecycle of an Ember.js application, starting from creating the application, through adding functionality into it all the way to running the test suites and starting the actual project in development mode.</p>\n<p>Almost everything that you do whilst developing an Ember.js application will involve this tool at some level, so it is important to understand how best to use it. We will be making use of it throughout this article.</p>\n<p>The first thing we need to do is ensure that the Ember.js CLI is correctly installed and up-to-date. This is done by installing from npm, as follows:</p>\n<pre><code class=\"bash language-bash\">$ npm install -g ember-cli\r\n</code></pre>\n<p>and we can check it was successfully installed by running the following command:</p>\n<pre><code class=\"bash language-bash\">$ ember --version\r\nember-cli: 2.15.0-beta.1\r\nnode: 8.2.1\r\nos: darwin x64\r\n</code></pre>\n<h2 id=\"creatingyourfirstemberjsapp\">Creating Your First Ember.js App</h2>\n<p>Once ember-cli is installed, you are ready to start creating your application. This is the first place we will be making use of the Ember.js CLI tool – it creates the entire application structure, setting everything up ready to run.</p>\n<pre><code class=\"bash language-bash\">$ ember new dice-roller\r\ninstalling app\r\n create .editorconfig\r\n create .ember-cli\r\n create .eslintrc.js\r\n create .travis.yml\r\n create .watchmanconfig\r\n create README.md\r\n create app/app.js\r\n create app/components/.gitkeep\r\n create app/controllers/.gitkeep\r\n create app/helpers/.gitkeep\r\n create app/index.html\r\n create app/models/.gitkeep\r\n create app/resolver.js\r\n create app/router.js\r\n create app/routes/.gitkeep\r\n create app/styles/app.css\r\n create app/templates/application.hbs\r\n create app/templates/components/.gitkeep\r\n create config/environment.js\r\n create config/targets.js\r\n create ember-cli-build.js\r\n create .gitignore\r\n create package.json\r\n create public/crossdomain.xml\r\n create public/robots.txt\r\n create testem.js\r\n create tests/.eslintrc.js\r\n create tests/helpers/destroy-app.js\r\n create tests/helpers/module-for-acceptance.js\r\n create tests/helpers/resolver.js\r\n create tests/helpers/start-app.js\r\n create tests/index.html\r\n create tests/integration/.gitkeep\r\n create tests/test-helper.js\r\n create tests/unit/.gitkeep\r\n create vendor/.gitkeep\r\nNPM: Installed dependencies\r\nSuccessfully initialized git.\r\n\r\n$\r\n</code></pre>\n<p>This has caused an entire application to be created which is ready to run. It has even set up Git as source control to track your work.</p>\n<blockquote>\n<p><strong>Note:</strong> If you wish, you can disable the Git integration and you can prefer Yarn over npm. The help for the tool describes this and much more.</p>\n</blockquote>\n<p>Now, let’s see what it looks like. Starting the Ember application for development purposes is – once again – also done using ember-cli:</p>\n<pre><code class=\"bash language-bash\">$ cd dice-roller\r\n$ ember serve\r\nLivereload server on http://localhost:49153\r\n'instrument' is imported from external module 'ember-data/-debug' but never used\r\nWarning: ignoring input sourcemap for vendor/ember/ember.debug.js because ENOENT: no such file or directory, open '/Users/coxg/source/me/writing/repos/dice-roller/tmp/source_map_concat-input_base_path-2fXNPqjl.tmp/vendor/ember/ember.debug.map'\r\nWarning: ignoring input sourcemap for vendor/ember/ember-testing.js because ENOENT: no such file or directory, open '/Users/coxg/source/me/writing/repos/dice-roller/tmp/source_map_concat-input_base_path-Xwpjztar.tmp/vendor/ember/ember-testing.map'\r\n\r\nBuild successful (5835ms) – Serving on http://localhost:4200/\r\n\r\n\r\n\r\nSlowest Nodes (totalTime => 5% ) | Total (avg)\r\n----------------------------------------------+---------------------\r\nBabel (16) | 4625ms (289 ms)\r\nRollup (1) | 445ms\r\n</code></pre>\n<p>We are now ready to go. The application is running on http://localhost:4200, and looks like this:<br />\n<img src=\"https://dab1nmslvvntp.cloudfront.net/wp-content/uploads/2017/10/1507570414first-view.png\" alt=\"Default application screen\" /></p>\n<p>It is also running a <a href=\"http://livereload.com/\">LiveReload</a> service which automatically watches for changes to the filesystem. This means that you can have an incredibly fast turnaround time when tweaking your site design. </p>\n<p>Let’s try it?</p>\n<p>The initial page already tells us what to do, so let’s go and change the main page and see what happens. We’re going to change the <code>app/templates/application.hbs</code> file to look like the following.</p>\n<pre><code class=\"handlebars language-handlebars\">This is my new application.\r\n\r\n{{outlet}}\r\n</code></pre>\n<blockquote>\n<p><strong>Note:</strong> The <code>{{outlet}}</code> tag is part of how Routing works in Ember. We will cover that later on.</p>\n</blockquote>\n<p>The first thing to notice is the output from ember-cli, which should look as follows:</p>\n<pre><code class=\"bash language-bash\">file changed templates/application.hbs\r\n\r\nBuild successful (67ms) – Serving on http://localhost:4200/\r\n\r\nSlowest Nodes (totalTime => 5% ) | Total (avg)\r\n----------------------------------------------+---------------------\r\nSourceMapConcat: Concat: App (1) | 9ms\r\nSourceMapConcat: Concat: Vendor /asset... (1) | 8ms\r\nSimpleConcatConcat: Concat: Vendor Sty... (1) | 4ms\r\nFunnel (7) | 4ms (0 ms)\r\n</code></pre>\n<p>This tells us that it has spotted that we changed the template and rebuilt and restarted everything. We’ve had zero involvement in that part of it.</p>\n<p>Now let’s look at the browser. If you’ve got LiveReload installed and running you will not even have needed to refresh the browser for this to be picked up, otherwise, you will need to reload the current page.</p>\n<p><img src=\"https://dab1nmslvvntp.cloudfront.net/wp-content/uploads/2017/10/1507570420first-change.png\" alt=\"First Change\" /></p>\n<p>Not very exciting, but this is with almost no effort on our part that we’ve achieved this.</p>\n<p>In addition, we get a fully set up test suite ready to run. This is – unsurprisingly – run using the Ember tool as well, as follows:</p>\n<pre><code class=\"bash language-bash\">$ ember test\r\n⠸ Building'instrument' is imported from external module 'ember-data/-debug' but never used\r\n⠴ BuildingWarning: ignoring input sourcemap for vendor/ember/ember.debug.js because ENOENT: no such file or directory, open '/Users/coxg/source/me/writing/repos/dice-roller/tmp/source_map_concat-input_base_path-S8aQFGaz.tmp/vendor/ember/ember.debug.map'\r\n⠇ BuildingWarning: ignoring input sourcemap for vendor/ember/ember-testing.js because ENOENT: no such file or directory, open '/Users/coxg/source/me/writing/repos/dice-roller/tmp/source_map_concat-input_base_path-wO8OLEE2.tmp/vendor/ember/ember-testing.map'\r\ncleaning up...\r\nBuilt project successfully. Stored in \"/Users/coxg/source/me/writing/repos/dice-roller/tmp/class-tests_dist-PUnMT5zL.tmp\".\r\nok 1 PhantomJS 2.1 - ESLint | app: app.js\r\nok 2 PhantomJS 2.1 - ESLint | app: resolver.js\r\nok 3 PhantomJS 2.1 - ESLint | app: router.js\r\nok 4 PhantomJS 2.1 - ESLint | tests: helpers/destroy-app.js\r\nok 5 PhantomJS 2.1 - ESLint | tests: helpers/module-for-acceptance.js\r\nok 6 PhantomJS 2.1 - ESLint | tests: helpers/resolver.js\r\nok 7 PhantomJS 2.1 - ESLint | tests: helpers/start-app.js\r\nok 8 PhantomJS 2.1 - ESLint | tests: test-helper.js\r\n\r\n1..8\r\n# tests 8\r\n# pass 8\r\n# skip 0\r\n# fail 0\r\n\r\n# ok\r\n</code></pre>\n<p>Note that the output talks about <a href=\"http://phantomjs.org/\">PhantomJS</a>. This is because there is full support for Integration tests that run in a browser, and by default, these run headless in the PhantomJS browser. There is full support for running them in other browsers if you wish, and when setting up continuous integration (CI) it is worth doing this to ensure that your application works correctly in all supported browsers.</p>\n<h3 id=\"howanemberjsappisstructured\">How an Ember.js app is structured</h3>\n<p>Before we get to actually writing our application, let’s explore how it is structured on the filesystem. The <code>ember new</code> command above will have created a whole directory structure on your computer, with lots of different parts. Understanding all of these is important to efficiently work with the tool and create amazing projects.</p>\n<p>At the very top level you will notice the following files and directories:</p>\n<ul>\n<li><strong>README.md</strong> – This is the standard readme file describing the application</li>\n<li><strong>package.json</strong> – This is the standard npm configuration file describing your application. This is used primarily for the dependencies to be installed correctly.</li>\n<li><strong>ember-cli-build.js</strong> – This is the configuration for the Ember CLI tool to power our build</li>\n<li><strong>testem.js</strong> – This is the configuration for the test framework. This allows you to define, amongst other things, the browsers that should be used to run the tests in for different environments.</li>\n<li><strong>app/</strong> – This is the actual application logic. A lot happens in here that will be covered below.</li>\n<li><strong>config/</strong> – This is the configuration for the application\n<ul>\n<li><strong>config/targets.js</strong> – This is a list of browsers to support. This is used by Babel to ensure that the Javascript is transpiled in such a way that they will all work.</li>\n<li><strong>config/environment.js</strong> – This is the main configuration for your application. Anything that is needed for the application, but that might vary from one environment to another, should be put in here.</li>\n</ul>\n</li>\n<li><strong>public/</strong> – This is any static resources that you wish to include in your application. For example, images and fonts.</li>\n<li><strong>vendor/</strong> – This is where any frontend dependencies that are not managed by the build system go</li>\n<li><strong>tests/</strong> – This is where all of the tests go\n<ul>\n<li><strong>tests/unit</strong> – This is all of the unit tests for the application</li>\n<li><strong>tests/integration</strong> – This is all of the integration tests for the application</li>\n</ul>\n</li>\n</ul>\n<h2 id=\"overallpagestructureincludingthirdpartycontent\">Overall Page Structure (Including Third-Party Content)</h2>\n<p>Before we get too far ahead, let’s give our page some form of structure. In this case, we are going to add in the <a href=\"http://materializecss.com/\">Materialize CSS framework</a> to give it a better look and feel.</p>\n<p>Adding in support for third-party content like this can be done in a number of ways:</p>\n<ul>\n<li>Linking directly to the content on an external service, like a CDN</li>\n<li>Using a package manager like npm or Bower to install it for us</li>\n<li>Including it directly in our application.</li>\n<li>Use of an <a href=\"https://guides.emberjs.com/v2.14.0/addons-and-dependencies/managing-dependencies/#toc_addons\">Ember Addon</a> if one is provided</li>\n</ul>\n<p>Unfortunately, the addon for Materialize doesn’t yet work with the latest version of Ember.js so, instead, we are simply going to link to the CDN resources from our main page. In order to achieve this, we are going to update <code>app/index.html</code>, which is the main page structure into which our application is rendered. We’re going to simply add the CDN links for jQuery, Google Icon Font, and Materialize.</p>\n<pre><code class=\"markup language-markup\"><!-- Inside the Head section -->\r\n <link href=\"https://fonts.googleapis.com/icon?family=Material+Icons\" rel=\"stylesheet\">\r\n <link rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/materialize/0.100.1/css/materialize.min.css\">\r\n\r\n<!-- Inside the Body section -->\r\n <script type=\"text/javascript\" src=\"https://code.jquery.com/jquery-3.2.1.min.js\"></script>\r\n <script src=\"https://cdnjs.cloudflare.com/ajax/libs/materialize/0.100.1/js/materialize.min.js\"></script>\r\n</code></pre>\n<p>Now we can update the main page to show our core template. This is done by editing <code>app/templates/application.hbs</code> to look like this:</p>\n<pre><code class=\"handlebars language-handlebars\"><nav>\r\n <div class=\"nav-wrapper\">\r\n <a href=\"#\" class=\"brand-logo\">\r\n <i class=\"material-icons\">filter_6</i>\r\n Dice Roller\r\n </a>\r\n <ul id=\"nav-mobile\" class=\"right hide-on-med-and-down\">\r\n </ul>\r\n </div>\r\n</nav>\r\n\r\n<div class=\"container\">\r\n {{outlet}}\r\n</div>\r\n</code></pre>\n<p>This gives us a Materialize Nav at the top of the screen, with a container containing that <code>{{outlet}}</code> tag mentioned earlier.</p>\n<p>This then looks like this when visited in your browser:<br />\n<img src=\"https://dab1nmslvvntp.cloudfront.net/wp-content/uploads/2017/10/1507570393layout.png\" alt=\"Our new layout\" /></p>\n<p>So what is this <code>outlet</code> tag? Ember works based off of routes, where each route is considered a child of some other route. The top-most route is handled by Ember automatically, and renders the template <code>app/templates/application.hbs</code>. </p>\n<p>The <code>outlet</code> tag specifies where Ember will render the next route in the current hierarchy – so the first level route is rendered into this tag in <code>application.hbs</code>, the second level route is rendered into this tag in that first level template, and so on.</p>\n<h2 id=\"creatinganewroute\">Creating a New Route</h2>\n<p>In an Ember.js application, every page that can be visited is accessed via a Route. There is a direct mapping between the URL that the browser opens and the route that the application renders.</p>\n<p>The easiest way to see this is by example. Let’s add a new route to our application allowing the user to actually roll some dice. Once again, this is done using the ember-cli tool.</p>\n<pre><code class=\"bash language-bash\">$ ember generate route roll\r\ninstalling route\r\n create app/routes/roll.js\r\n create app/templates/roll.hbs\r\nupdating router\r\n add route roll\r\ninstalling route-test\r\n create tests/unit/routes/roll-test.js\r\n</code></pre>\n<p>What this one command has given us is:</p>\n<ul>\n<li>A handler for the route – <code>app/routes/roll.js</code></li>\n<li>A template for the route – <code>app/templates/roll.hbs</code></li>\n<li>A test for the route – <code>tests/unit/routes/roll-test.js</code></li>\n<li>Updated the router configuration to know about this new route – <code>app/router.js</code></li>\n</ul>\n<p>Let’s see this in action. For now, we’re going to have a very simple page allowing us to roll a number of dice. To do so, update <code>app/templates/roll.hbs</code> as follows:</p>\n<pre><code class=\"handlebars language-handlebars\"><div class=\"row\">\r\n <form class=\"col s12\">\r\n <div class=\"row\">\r\n <div class=\"input-field col s12\">\r\n <input placeholder=\"Name\" id=\"roll_name\" type=\"text\" class=\"validate\">\r\n <label for=\"roll_name\">Name of Roll</label>\r\n </div>\r\n </div>\r\n <div class=\"row\">\r\n <div class=\"input-field col s6\">\r\n <input placeholder=\"Number of dice\" id=\"number_of_dice\" type=\"number\" class=\"validate\" value=\"1\">\r\n <label for=\"number_of_dice\">Number of Dice</label>\r\n </div>\r\n <div class=\"input-field col s6\">\r\n <input placeholder=\"Number of sides\" id=\"number_of_sides\" type=\"number\" class=\"validate\" value=\"6\">\r\n <label for=\"number_of_sides\">Number of Sides</label>\r\n </div>\r\n </div>\r\n <div class=\"row\">\r\n <button class=\"btn waves-effect waves-light\" type=\"submit\" name=\"action\">\r\n Roll Dice\r\n <i class=\"material-icons right\">send</i>\r\n </button>\r\n </div>\r\n </form>\r\n</div>\r\n\r\n{{outlet}}\r\n</code></pre>\n<p>Then visit http://localhost:4200/roll and see the result:<br />\n<img src=\"https://dab1nmslvvntp.cloudfront.net/wp-content/uploads/2017/10/1507570389roll.png\" alt=\"The Roll Dice page\" /></p>\n<p>Now we need to be able to get here. Ember makes this very simple to achieve by use of the <code>link-to</code> tag. This takes (among other things) the name of the route that we are sending the user to and then renders markup to get the user there. </p>\n<p>For our case, we will be updating <code>app/templates/application.hbs</code> to contain the following:</p>\n<pre><code class=\"markup language-markup\"><ul id=\"nav-mobile\" class=\"right hide-on-med-and-down\">\r\n {{#link-to 'roll' tagName=\"li\"}}\r\n <a href=\"roll\">Roll Dice</a>\r\n {{/link-to}}\r\n</ul>\r\n</code></pre>\n<p>Which makes our header bar look as follows:</p>\n<p><img src=\"https://dab1nmslvvntp.cloudfront.net/wp-content/uploads/2017/10/1507570402header-link.png\" alt=\"Header Link\" /></p>\n<p>This new link then takes the user to the “/roll” route that we’ve just set up, exactly as desired.</p>\n<h2 id=\"creatingmodularcomponents\">Creating Modular Components</h2>\n<p>If you actually test the application so far you will notice one problem. Opening the home page and visiting the “/roll” link works, but the labels on the form don’t line up properly. This is because Materialize needs to trigger some JavaScript to sort things out, but the dynamic routing means that the page isn’t being reloaded. We will need to help out a bit here. </p>\n<p>Enter components. Components are pieces of UI that have a full lifecycle and can be interacted with. They are also the way that you will create reusable UI elements if you need to do so – we will see this later.</p>\n<p>For now, we are going to create a single component representing the Roll Dice form. As always, generating the component is done with our ember-cli tool, as follows:</p>\n<pre><code class=\"bash language-bash\">$ ember generate component roll-dice\r\ninstalling component\r\n create app/components/roll-dice.js\r\n create app/templates/components/roll-dice.hbs\r\ninstalling component-test\r\n create tests/integration/components/roll-dice-test.js\r\n</code></pre>\n<p>This has given us:</p>\n<ul>\n<li><strong>app/components/roll-dice.js</strong> – The code that powers the component</li>\n<li><strong>app/templates/components/roll-dice.hbs</strong> – The template that controls how it will look</li>\n<li><strong>tests/integration/components/roll-dice-test.js</strong> – A test to ensure the component works correctly</li>\n</ul>\n<p>We’re going to move all of our markup into the component now – which will do nothing to the way the application works directly but makes it easy for us to do so in a bit.</p>\n<p>Update <code>app/templates/components/roll-dice.hbs</code> to read as follows:</p>\n<pre><code class=\"markup language-markup\"><form class=\"col s12\">\r\n <div class=\"row\">\r\n <div class=\"input-field col s12\">\r\n <input placeholder=\"Name\" id=\"roll_name\" type=\"text\" class=\"validate\">\r\n <label for=\"roll_name\">Name of Roll</label>\r\n </div>\r\n </div>\r\n <div class=\"row\">\r\n <div class=\"input-field col s6\">\r\n <input placeholder=\"Number of dice\" id=\"number_of_dice\" type=\"number\" class=\"validate\" value=\"1\">\r\n <label for=\"number_of_dice\">Number of Dice</label>\r\n </div>\r\n <div class=\"input-field col s6\">\r\n <input placeholder=\"Number of sides\" id=\"number_of_sides\" type=\"number\" class=\"validate\" value=\"6\">\r\n <label for=\"number_of_sides\">Number of Sides</label>\r\n </div>\r\n </div>\r\n <div class=\"row\">\r\n <button class=\"btn waves-effect waves-light\" type=\"submit\" name=\"action\">\r\n Roll Dice\r\n <i class=\"material-icons right\">send</i>\r\n </button>\r\n </div>\r\n</form>\r\n</code></pre>\n<p>And then update app/templates/roll.hbs as follows:</p>\n<pre><code class=\"handlebars language-handlebars\"><div class=\"row\">\r\n {{roll-dice}}\r\n</div>\r\n\r\n{{outlet}}\r\n</code></pre>\n<p>The template for our component is exactly the markup that we previously had in our route, and our route is significantly simpler now. The <code>roll-dice</code> tag is what tells Ember to render our component in the right place. </p>\n<p>If we were to run this now we would see no functional difference at all, but our code is slightly more modular this way. We’re going to take advantage of the component to fix our rendering glitch and to add some functionality to our system.</p>\n<h3 id=\"thecomponentlifecycle\">The component lifecycle</h3>\n<p>Ember components have a defined lifecycle that they follow, with a number of hooks that can be triggered at different stages. We are going to make use of the <code>didRender</code> hook which is called after the component is rendered – either for the first time or any subsequent times – to ask Materialize to update the labels on the text fields.</p>\n<p>This is done by updating the code behind the component, found inside <code>app/components/roll-dice.js</code>, to look like this:</p>\n<pre><code class=\"javascript language-javascript\">/* global Materialize:false */\r\nimport Ember from 'ember';\r\n\r\nexport default Ember.Component.extend({\r\n didRender() {\r\n Materialize.updateTextFields();\r\n }\r\n});\r\n</code></pre>\n<p>Now, every time you visit the “/roll” route – whether it’s by deep linking to it or by using our header link – this code is run and Materialize will update the labels to flow correctly.</p>\n<h3 id=\"databinding\">Data binding</h3>\n<p>We also want to be able to get data in and out of our UI via our component. This is remarkably easy to achieve but, surprisingly, the Ember guide doesn’t cover it, so it looks harder than it should be.</p>\n<p>Every piece of data that we want to interact with exists on the Component class as it’s own field. We then use some helpers to render our input fields on our component that do the work of binding these input fields to the component variables, so that we can interact with them directly without ever needing to be concerned with the DOM activities.</p>\n<p>In this case, we have three fields so we need to add the following three lines to <code>app/components/roll-dice.js</code>, just inside the component definition:</p>\n<pre><code class=\"javascript language-javascript\"> rollName: '',\r\n numberOfDice: 1,\r\n numberOfSides: 6,\r\n</code></pre>\n<p>Then we update our template to render using the helpers instead of directly rendering HTML markup. To do this, replace the <code><input></code> tags as follows:</p>\n<pre><code class=\"markup language-markup\"><div class=\"row\">\r\n <div class=\"input-field col s12\">\r\n <!-- This replaces the <input> tag for \"roll_name\" -->\r\n {{input placeholder=\"Name\" id=\"roll_name\" class=\"validate\" value=(mut rollName)}}\r\n <label for=\"roll_name\">Name of Roll</label>\r\n </div>\r\n</div>\r\n<div class=\"row\">\r\n <div class=\"input-field col s6\">\r\n <!-- This replaces the <input> tag for \"number_of_dice\" -->\r\n {{input placeholder=\"Number of dice\" id=\"number_of_dice\" type=\"number\" class=\"validate\" value=(mut numberOfDice)}}\r\n <label for=\"number_of_dice\">Number of Dice</label>\r\n </div>\r\n <div class=\"input-field col s6\">\r\n <!-- This replaces the <input> tag for \"number_of_sides\" -->\r\n {{input placeholder=\"Number of sides\" id=\"number_of_sides\" type=\"number\" class=\"validate\" value=(mut numberOfSides)}}\r\n <label for=\"number_of_sides\">Number of Sides</label>\r\n </div>\r\n</div>\r\n</code></pre>\n<p>Note that the <code>value</code> attribute has a slightly odd-looking syntax. This syntax can be used for any attribute on the tag, not only <code>value</code>. There are three ways that this can be used:</p>\n<ul>\n<li>As a quoted string – the value is used as-is</li>\n<li>As an unquoted string – the value is populated from this piece of data on the component, but the component is never updated</li>\n<li>As <code>(mut <name>)</code> – the value is populated from this piece of data on the component, and the component is <strong>mut</strong>ated when the value changes in the browser</li>\n</ul>\n<p>All of the above means that we can now access those three fields we defined in our component as if they were the values of our input boxes, and Ember ensures that everything works correctly like that.</p>\n<h3 id=\"componentactions\">Component actions</h3>\n<p>The next thing we want to do is interact with the component. Specifically, it would be good to handle when our “Roll Dice” button is clicked. Ember handles this with Actions – which are pieces of code in your component that can be hooked into your template. Actions are simply defined as functions in our component class, inside a special field called <code>actions</code>, which implement our desired functionality.</p>\n<p>For now, we are simply going to tell the user what they want to do, but not actually do anything – that comes next. This will use an <strong>On Submit</strong> action on the form itself, which means that it gets triggered if they click on the button <em>or</em> they press enter in one of the fields.</p>\n<p>Our actions code block inside of <code>app/components/roll-dice.hbs</code> is going to look like this:</p>\n<pre><code class=\"jsx language-jsx\"> actions: {\r\n triggerRoll() {\r\n alert(`Rolling ${this.numberOfDice}D${this.numberOfSides} as \"${this.rollName}\"`);\r\n return false;\r\n }\r\n }\r\n</code></pre>\n<p>We return <code>false</code> to prevent <a href=\"https://www.sitepoint.com/event-bubbling-javascript/\">event bubbling</a>. This is fairly standard behavior in HTML applications and is essential in this case to stop the form submission from reloading the page.</p>\n<p>You will note that we refer to our fields that we previously defined for accessing the input fields. There is no DOM access at all here – it’s all just interacting with JavaScript variables.</p>\n<p>Now we just need to wire this up. In our template, we need to tell the form tag that it needs to trigger this action when the <code>onsubmit</code> event is triggered. This is just adding a single attribute to the form tag using an Ember helper to wire it up to our action. This looks as follows inside <code>app/templates/components/roll-dice.hbs</code>:</p>\n<pre><code class=\"markup language-markup\"><form class=\"col s12\" onsubmit={{action 'triggerRoll'}}>\r\n</code></pre>\n<p>We can now click on the button, having filled out our form, and get a alert popup telling us what we’ve done.</p>\n<p><img src=\"https://dab1nmslvvntp.cloudfront.net/wp-content/uploads/2017/10/1507570432alert.png\" alt=\"Action Alert box\" /></p>\n<h2 id=\"managingdatabetweenclientandserver\">Managing Data Between Client and Server</h2>\n<p>The next thing we want to do is actually roll some dice. This is going to involve some communication with the server – since the server is responsible for rolling the dice and remembering the results. </p>\n<p>Our desired flow here is:</p>\n<ul>\n<li>Users specifies the dice they wish to roll</li>\n<li>User presses the “Roll Dice” button</li>\n<li>Browser sends the details to the server</li>\n<li>Server rolls the dice, remembers the result, and sends the results back to the client</li>\n<li>Browser displays the results of rolling the dice</li>\n</ul>\n<p>Sounds simple enough. And, of course, with Ember it really is.</p>\n<p>Ember handles this using an inbuilt concept of a Store populated with Models. The Store is the single source of knowledge throughout the entire application, and each Model is a single piece of information in the store. Models all know how to persist themselves to the backend, and the Store knows how to create and access Models.</p>\n<h2 id=\"passingcontrolfromcomponentstoroutes\">Passing Control from Components to Routes</h2>\n<p>Throughout our application, it is important to keep the encapsulation correct. Routes (and controllers, which we haven’t covered) have access to the store. Components do not. </p>\n<p>This is because the route represents a specific piece of functionality in your application, whereas the component represents a small piece of UI. In order to work with this, the component has the ability to send a signal up the hierarchy that some action has happened – in a very similar way that our DOM components could signal to our component that something has happened.</p>\n<p>Firstly then, let’s move our logic for displaying the alert box into the route instead of the component. In order to do this, we need to change the following areas of code:</p>\n<p>In the logic behind our route – <code>app/routes/roll.js</code> – we need to add the following block to register the action that we are going to perform.</p>\n<pre><code class=\"jsx language-jsx\">actions: {\r\n saveRoll: function(rollName, numberOfDice, numberOfSides) {\r\n alert(`Rolling ${numberOfDice}D${numberOfSides} as \"${rollName}\"`);\r\n }\r\n}\r\n</code></pre>\n<p>In the logic behind our component – <code>app/components/roll-dice.js</code> – we need to trigger an action on our component when we ourselves are triggered. This is done using the <code>sendAction</code> mechanism inside our preexisting action handler.</p>\n<pre><code class=\"jsx language-jsx\">triggerRoll() {\r\n this.sendAction('roll', this.rollName, this.numberOfDice, this.numberOfSides);\r\n return false;\r\n}\r\n</code></pre>\n<pre><code>\r\n</code></pre>\n<p>And finally, we need to wire the action up. This is done in the template for the route – <code>app/templates/roll.hbs</code> – by changing the way that our component is rendered:</p>\n<pre><code class=\"markup language-markup\">{{roll-dice roll=\"saveRoll\" }}\r\n</code></pre>\n<p>This tells the component that the property <code>roll</code> is linked to the action <code>saveRoll</code> inside our route. This name <code>roll</code> is then used inside our component to indicate to the caller that a dice roll has been done. This name makes sense to our component – because it knows that it is requesting a dice roll to be performed, but doesn’t care how the other code does so or what it will do with the information.</p>\n<p>Again, running this will cause no functional difference in our application, but just means that the pieces are all in the right place.</p>\n<h2 id=\"persistingtothestore\">Persisting to the Store</h2>\n<p>Before we are able to persist data into our store, we need to define a model to represent it. This is done by using our trusty ember-cli tool again to create the structure and then populating it.</p>\n<p>To create the model class we execute:</p>\n<pre><code class=\"bash language-bash\">$ ember generate model roll\r\ninstalling model\r\n create app/models/roll.js\r\ninstalling model-test\r\n create tests/unit/models/roll-test.js\r\n</code></pre>\n<p>Then we tell our model about the attributes it needs to understand. This is done by modifying <code>app/models/roll.js</code> to look like the following:</p>\n<pre><code class=\"jsx language-jsx\">import DS from 'ember-data';\r\n\r\nexport default DS.Model.extend({\r\n rollName: DS.attr('string'),\r\n numberOfDice: DS.attr('number'),\r\n numberOfSides: DS.attr('number'),\r\n result: DS.attr('number')\r\n});\r\n</code></pre>\n<p>The <code>DS.attr</code> calls define a new attribute of the specified type – called a Transform in Ember. The default options here are “string”, “number”, “date” and “boolean”, though you can define your own if necessary.</p>\n<p>Now we can actually use this to create or roll. This is done by accessing the store from our action we now have in <code>app/routes/roll.js</code>:</p>\n<pre><code class=\"jsx language-jsx\">saveRoll: function(rollName, numberOfDice, numberOfSides) {\r\n let result = 0;\r\n for (let i = 0; i < numberOfDice; ++i) {\r\n result += 1 + (parseInt(Math.random() * numberOfSides));\r\n }\r\n\r\n const store = this.get('store');\r\n // This requests that the store give us an instance of our \"roll\" model with the given data\r\n const roll = store.createRecord('roll', {\r\n rollName,\r\n numberOfDice,\r\n numberOfSides,\r\n result\r\n });\r\n // This tells our model to save itself to our backend\r\n roll.save();\r\n}\r\n</code></pre>\n<p>If we try this out, we will now see that pressing our <em>Roll Dice</em> button causes a network call to be made to our server. This fails, because our server isn’t yet expecting it, but it’s progress.</p>\n<p><img src=\"https://dab1nmslvvntp.cloudfront.net/wp-content/uploads/2017/10/1507570427create-roll.png\" alt=\"Create Roll\" /></p>\n<p>We’re not focusing on the backend here, so we’re going to concern ourselves with this. If you need to develop an Ember application without a backend at all then there are options – such as the <a href=\"https://github.com/locks/ember-localstorage-adapter\">ember-localstorage-adapter</a> that will work entirely within the browser. Alternatively, you simply need to write the appropriate server and ensure that the server and client are hosted correctly and it will all work.</p>\n<h2 id=\"loadingfromthestore\">Loading from the Store</h2>\n<p>Now that we’ve got some data into our store, we need to get it back out again. At the same time, we’re going to write an index route – the one that is used when you access the home page.</p>\n<p>Ember implicitly has a route called <code>index</code> that is used to render the initial page of the application. If the files for this route do not exist then no error is raised but, instead, nothing is rendered. We are going to use this route to render all of the historical rolls from our store.</p>\n<p>Because the index route already implicitly exists, there is no need to use the ember-cli tool – we can directly create the files and it is already wired up.</p>\n<p>Our route handler will go into <code>app/routes/index.js</code> and will look as follows:</p>\n<pre><code class=\"jsx language-jsx\">import Ember from 'ember';\r\n\r\nexport default Ember.Route.extend({\r\n model() {\r\n return this.get('store').findAll('roll');\r\n }\r\n});\r\n</code></pre>\n<p>Here, our route has direct access to the store and can use the <code>findAll</code> method to load every roll that has been persisted. We then provide these to the template by use of the <code>model</code> method.</p>\n<p>Our template will then go into <code>app/templates/index.hbs</code> as follows:</p>\n<pre><code class=\"markup language-markup\"><table>\r\n <thead>\r\n <tr>\r\n <th>Name</th>\r\n <th>Dice Rolled</th>\r\n <th>Result</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n {{#each model as |roll|}}\r\n <tr>\r\n <td>{{roll.rollName}}</td>\r\n <td>{{roll.numberOfDice}}D{{roll.numberOfSides}}</td>\r\n <td>{{roll.result}}</td>\r\n </tr>\r\n {{/each}}\r\n </tbody>\r\n</table>\r\n\r\n\r\n{{outlet}}\r\n</code></pre>\n<p>This can access the model from the route directly, and then iterates over it to produce the table rows. This will then look as follows:</p>\n<p><img src=\"https://dab1nmslvvntp.cloudfront.net/wp-content/uploads/2017/10/1507570398history.png\" alt=\"History page\" /></p>\n<h2 id=\"summary\">Summary</h2>\n<p>At this point, after relatively little work, we have developed an application that will allow us to roll dice and see a history of all rolls. This includes data binding from our form, persisting data into a store, and reading it back out, templating support to display all of the pages, and full URL routing throughout. This application can be developed from scratch in under an hour.</p>\n<p>Using Ember can greatly improve the efficiency with which you develop your frontend. Unlike libraries such as React, Ember gives you the entire suite of functionality necessary to build a fully functional application without needing any extra tools. The addition of the <code>ember-cli</code> and the out-of-the-box setup then takes this to the next level, making the process incredibly simple and painless from beginning to end. Coupled with the <a href=\"https://www.emberjs.com/community/\">community support</a> there is almost nothing that can’t be achieved.</p>\n<p>Unfortunately, it can be difficult to slot Ember into an existing project. It works best when starting a new project. Fitting it into an existing one can be difficult or impossible. Ember also works out of the box with a very specific way of working with backends, and if your existing backend does not comply with this then you could end up spending a lot of time and effort either re-working the backend or finding/writing plugins to talk to the existing one.</p>\n<p>Ember has a lot of power and can allow you to very quickly create full-featured application frontends. It does impose a lot of structure on how you must design your code, but this is often less restrictive than it first seems since this structure is necessary anyway.</p>\n","protected":false},"excerpt":{"rendered":"<p class=\"wp-special\">Ember.js is an opinionated frontend JavaScript framework that has been getting a lot of interest lately. This article will introduce some key concepts of the framework while building a simple application with it, in order to show a basic example of what it is capable of producing.</p>\n<p>Our example application is going to be a Dice Roller, including the ability to roll some dice and view a history of all dice rolls that have been performed to date. A fully working version of this application is available from <a href=\"https://github.com/sazzer/dice-roller\">Github</a></p>\n<p>The Ember.js framework pulls together a lot of modern JavaScript concepts and technologies into one single bundle, including but not limited to:</p>\n<ul>\n<li>The use of the <a href=\"https://babeljs.io/\">Babel</a> transpiler tool, to support ES2016 throughout.</li>\n<li>Testing support at the Unit, Integration and Acceptance levels as standard, powered by <a href=\"https://github.com/testem/testem\">Testem</a> and <a href=\"https://qunitjs.com/\">QTest</a>.</li>\n<li>Asset building using <a href=\"http://broccolijs.com/\">Broccoli.js</a>.</li>\n<li>Support for live reloading, for shorter development cycle times.</li>\n<li>Templating using the <a href=\"http://handlebarsjs.com/\">Handlebars</a> markup syntax.</li>\n<li>URL Routing first development to ensure that deep linking is fully supported throughout.</li>\n<li>Full data layer built around <a href=\"http://jsonapi.org/\">JSON API</a>, but pluggable for whatever API access you need.</li>\n</ul>\n<p>In order to work with Ember.js, it is assumed that you have an up-to-date installation of Node.js and npm. If not then these can be downloaded and installed from the <a href=\"https://nodejs.org/\">Node.js website</a>.</p>\n<p>It should also be mentioned that Ember is purely a frontend framework. It has a number of ways of interacting with the backend of your choice, but this backend is not in any way handled by Ember itself. </p>\n<h2 id=\"introducingembercli\">Introducing ember-cli</h2>\n<p>A lot of the power of Ember.js comes from its command line interface (CLI). This tool – known as <code>ember-cli</code> – powers much of the development lifecycle of an Ember.js application, starting from creating the application, through adding functionality into it all the way to running the test suites and starting the actual project in development mode. </p>\n<p>Almost everything that you do whilst developing an Ember.js application will involve this tool at some level, so it is important to understand how best to use it. We will be making use of it throughout this article.</p>\n<p>The first thing we need to do is ensure that the Ember.js CLI is correctly installed and up-to-date. This is done by installing from npm, as follows:</p>\n<pre><code class=\"bash language-bash\">$ npm install -g ember-cli\r\n</code></pre>\n<p>and we can check it was successfully installed by running the following command:</p>\n<pre><code class=\"bash language-bash\">$ ember --version\r\nember-cli: 2.15.0-beta.1\r\nnode: 8.2.1\r\nos: darwin x64\r\n</code></pre>\n<h2 id=\"creatingyourfirstemberjsapp\">Creating Your First Ember.js App</h2>\n<p>Once ember-cli is installed, you are ready to start creating your application. This is the first place we will be making use of the Ember.js CLI tool – it creates the entire application structure, setting everything up ready to run.</p>\n<pre><code class=\"bash language-bash\">$ ember new dice-roller\r\ninstalling app\r\n create .editorconfig\r\n create .ember-cli\r\n create .eslintrc.js\r\n create .travis.yml\r\n create .watchmanconfig\r\n create README.md\r\n create app/app.js\r\n create app/components/.gitkeep\r\n create app/controllers/.gitkeep\r\n create app/helpers/.gitkeep\r\n create app/index.html\r\n create app/models/.gitkeep\r\n create app/resolver.js\r\n create app/router.js\r\n create app/routes/.gitkeep\r\n create app/styles/app.css\r\n create app/templates/application.hbs\r\n create app/templates/components/.gitkeep\r\n create config/environment.js\r\n create config/targets.js\r\n create ember-cli-build.js\r\n create .gitignore\r\n create package.json\r\n create public/crossdomain.xml\r\n create public/robots.txt\r\n create testem.js\r\n create tests/.eslintrc.js\r\n create tests/helpers/destroy-app.js\r\n create tests/helpers/module-for-acceptance.js\r\n create tests/helpers/resolver.js\r\n create tests/helpers/start-app.js\r\n create tests/index.html\r\n create tests/integration/.gitkeep\r\n create tests/test-helper.js\r\n create tests/unit/.gitkeep\r\n create vendor/.gitkeep\r\nNPM: Installed dependencies\r\nSuccessfully initialized git.\r\n\r\n$\r\n</code></pre>\n<p>This has caused an entire application to be created which is ready to run. It has even set up Git as source control to track your work.</p>\n<blockquote>\n<p><strong>Note:</strong> If you wish, you can disable the Git integration and you can prefer Yarn over npm. The help for the tool describes this and much more.</p>\n</blockquote>\n<p>Now, let’s see what it looks like. Starting the Ember application for development purposes is – once again – also done using ember-cli:</p>\n<pre><code class=\"bash language-bash\">$ cd dice-roller\r\n$ ember serve\r\nLivereload server on http://localhost:49153\r\n'instrument' is imported from external module 'ember-data/-debug' but never used\r\nWarning: ignoring input sourcemap for vendor/ember/ember.debug.js because ENOENT: no such file or directory, open '/Users/coxg/source/me/writing/repos/dice-roller/tmp/source_map_concat-input_base_path-2fXNPqjl.tmp/vendor/ember/ember.debug.map'\r\nWarning: ignoring input sourcemap for vendor/ember/ember-testing.js because ENOENT: no such file or directory, open '/Users/coxg/source/me/writing/repos/dice-roller/tmp/source_map_concat-input_base_path-Xwpjztar.tmp/vendor/ember/ember-testing.map'\r\n\r\nBuild successful (5835ms) – Serving on http://localhost:4200/\r\n\r\n\r\n\r\nSlowest Nodes (totalTime => 5% ) | Total (avg)\r\n----------------------------------------------+---------------------\r\nBabel (16) | 4625ms (289 ms)\r\nRollup (1) | 445ms\r\n</code></pre>\n<p>We are now ready to go. The application is running on http://localhost:4200, and looks like this:<br />\n<img src=\"https://dab1nmslvvntp.cloudfront.net/wp-content/uploads/2017/10/1507570414first-view.png\" alt=\"Default application screen\" /></p>\n<p>It is also running a <a href=\"http://livereload.com/\">LiveReload</a> service which automatically watches for changes to the filesystem. This means that you can have an incredibly fast turnaround time when tweaking your site design. </p>\n<p>Let’s try it?</p>\n<p>The initial page already tells us what to do, so let’s go and change the main page and see what happens. We’re going to change the <code>app/templates/application.hbs</code> file to look like the following.</p>\n<pre><code class=\"handlebars language-handlebars\">This is my new application.\r\n\r\n{{outlet}}\r\n</code></pre>\n<blockquote>\n<p><strong>Note:</strong> The <code>{{outlet}}</code> tag is part of how Routing works in Ember. We will cover that later on.</p>\n</blockquote>\n<p>The first thing to notice is the output from ember-cli, which should look as follows:</p>\n<pre><code class=\"bash language-bash\">file changed templates/application.hbs\r\n\r\nBuild successful (67ms) – Serving on http://localhost:4200/\r\n\r\nSlowest Nodes (totalTime => 5% ) | Total (avg)\r\n----------------------------------------------+---------------------\r\nSourceMapConcat: Concat: App (1) | 9ms\r\nSourceMapConcat: Concat: Vendor /asset... (1) | 8ms\r\nSimpleConcatConcat: Concat: Vendor Sty... (1) | 4ms\r\nFunnel (7) | 4ms (0 ms)\r\n</code></pre>\n<p>This tells us that it has spotted that we changed the template and rebuilt and restarted everything. We’ve had zero involvement in that part of it.</p>\n<p>Now let’s look at the browser. If you’ve got LiveReload installed and running you will not even have needed to refresh the browser for this to be picked up, otherwise, you will need to reload the current page.</p>\n<p><img src=\"https://dab1nmslvvntp.cloudfront.net/wp-content/uploads/2017/10/1507570420first-change.png\" alt=\"First Change\" /></p>\n<p>Not very exciting, but this is with almost no effort on our part that we’ve achieved this.</p>\n<p>In addition, we get a fully set up test suite ready to run. This is – unsurprisingly – run using the Ember tool as well, as follows:</p>\n<pre><code class=\"bash language-bash\">$ ember test\r\n⠸ Building'instrument' is imported from external module 'ember-data/-debug' but never used\r\n⠴ BuildingWarning: ignoring input sourcemap for vendor/ember/ember.debug.js because ENOENT: no such file or directory, open '/Users/coxg/source/me/writing/repos/dice-roller/tmp/source_map_concat-input_base_path-S8aQFGaz.tmp/vendor/ember/ember.debug.map'\r\n⠇ BuildingWarning: ignoring input sourcemap for vendor/ember/ember-testing.js because ENOENT: no such file or directory, open '/Users/coxg/source/me/writing/repos/dice-roller/tmp/source_map_concat-input_base_path-wO8OLEE2.tmp/vendor/ember/ember-testing.map'\r\ncleaning up...\r\nBuilt project successfully. Stored in \"/Users/coxg/source/me/writing/repos/dice-roller/tmp/class-tests_dist-PUnMT5zL.tmp\".\r\nok 1 PhantomJS 2.1 - ESLint | app: app.js\r\nok 2 PhantomJS 2.1 - ESLint | app: resolver.js\r\nok 3 PhantomJS 2.1 - ESLint | app: router.js\r\nok 4 PhantomJS 2.1 - ESLint | tests: helpers/destroy-app.js\r\nok 5 PhantomJS 2.1 - ESLint | tests: helpers/module-for-acceptance.js\r\nok 6 PhantomJS 2.1 - ESLint | tests: helpers/resolver.js\r\nok 7 PhantomJS 2.1 - ESLint | tests: helpers/start-app.js\r\nok 8 PhantomJS 2.1 - ESLint | tests: test-helper.js\r\n\r\n1..8\r\n# tests 8\r\n# pass 8\r\n# skip 0\r\n# fail 0\r\n\r\n# ok\r\n</code></pre>\n<p>Note that the output talks about <a href=\"http://phantomjs.org/\">PhantomJS</a>. This is because there is full support for Integration tests that run in a browser, and by default, these run headless in the PhantomJS browser. There is full support for running them in other browsers if you wish, and when setting up continuous integration (CI) it is worth doing this to ensure that your application works correctly in all supported browsers.</p>\n<h3 id=\"howanemberjsappisstructured\">How an Ember.js app is structured</h3>\n<p>Before we get to actually writing our application, let’s explore how it is structured on the filesystem. The <code>ember new</code> command above will have created a whole directory structure on your computer, with lots of different parts. Understanding all of these is important to efficiently work with the tool and create amazing projects.</p>\n","protected":false},"author":72508,"featured_media":101094,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[4568,407],"tags":[4554,9543],"_links":{"self":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/posts/160604"}],"collection":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/posts"}],"about":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/types/post"}],"author":[{"embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/users/72508"}],"replies":[{"embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/comments?post=160604"}],"version-history":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/posts/160604/revisions"}],"wp_featuredmedia":[{"embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/media/101094"}],"wp_attachment":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/media?parent=160604"}],"wp_term":[{"taxonomy":"category","embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/categories?post=160604"},{"taxonomy":"post_tag","embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/tags?post=160604"}],"curies":[{"name":"wp","href":"https://api.w.org/{rel}","templated":true}]}}
{"index":{"_index":"blogs","_id":160623,"_type":"default"}}
{"id":160623,"date":"2017-10-16T09:00:17","date_gmt":"2017-10-16T16:00:17","guid":{"rendered":"https://www.sitepoint.com/?p=160623"},"modified":"2017-10-16T16:25:31","modified_gmt":"2017-10-16T23:25:31","slug":"a-css-framework-in-6-minutes-with-bulma","status":"publish","type":"post","link":"https://www.sitepoint.com/a-css-framework-in-6-minutes-with-bulma/","title":{"rendered":"Learn a CSS Framework in 6 Minutes with Bulma"},"content":{"rendered":"<div style=\"position:relative;height:0;padding-bottom:56.25%\"><iframe src=\"https://www.youtube.com/embed/MchBPICewgs?ecver=2\" style=\"position:absolute;width:100%;height:100%;left:0\" width=\"640\" height=\"360\" frameborder=\"0\" allowfullscreen></iframe></div>\n<p>In this tutorial, we’ll be getting started with Bulma, a modern CSS Framework built on Flexbox. For best results, follow along with the video at the end by <a href=\"http://codepop.com/open-sourcecraft/?utm_source=sitepoint&utm_medium=article&utm_campaign=open_sourcecraft_bulma&utm_content=top\">OpenSource Craft</a>. If you want to learn why you should care about Bulma, check out <a href=\"https://www.youtube.com/watch?v=bCTdyfHfUaI&feature=youtu.be\">this video</a>.</p>\n<p>We’ll be building a Coding Quotes page, utilizing Bulma’s UI components including a Hero banner, Columns, Cards, Buttons and more.<br />\n<img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508124301image1-1024x590.png\" alt=\"Bulma Example 1\" width=\"1024\" height=\"590\" class=\"aligncenter size-large wp-image-160647\" /></p>\n<p>First, let’s install Bulma. You can quickly do so from the command line with <strong>npm install Bulma</strong>, or you can import the project like I have, with the following lines of code. The first line imports the Font Awesome library so we can use their icons.</p>\n<pre><code class='language-markup'><link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css\"/>\r\n\r\n<link rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/bulma/0.5.1/css/bulma.min.css\"/></code></pre>\n<p>Next, we’ll create the <a href=\"http://bulma.io/documentation/layout/hero/?utm_source=sitepoint&utm_medium=article&utm_campaign=open_sourcecraft_bulma\">Hero banner</a> with a section element and the Bulma class <code>hero</code> and a div with the class of <code>hero-body</code>.</p>\n<pre><code class='language-markup'><section class=\"hero\">\r\n <div class=\"hero-body\"></div>\r\n</section></code></pre>\n<p>Then we’ll add some modifier classes to give the banner the primary color of our design with <code>is-primary</code>, and we’ll adjust its size with <code>is-medium</code>. Bulma’s class names and modifiers are readable and quite literal.</p>\n<pre><code class='language-markup'><section class=\"hero is-primary is-medium\">\r\n <div class=\"hero-body\"></div>\r\n</section></code></pre>\n<p>Within our <code>hero-body</code> div, we’ll add a <code>container</code> div for our <code>h1</code> and <code>h2</code>, which we’ll style as a <code>title</code> and <code>subtitle</code>, respectively. Giving the title an <code>is-1</code> modifier will make it large.</p>\n<pre><code class='language-markup'><div class=\"container\">\r\n <h1 class=\"title is-1\">\r\n Coding Quotes\r\n </h1>\r\n <h2 class=\"subtitle\">\r\n Like your favorites\r\n </h2>\r\n </div></code></pre>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508124306image4-1024x198.png\" alt=\"Bulma Example 4\" width=\"1024\" height=\"198\" class=\"aligncenter size-large wp-image-160650\" /></p>\n<p>That completes the top of our site, now let’s build some columns. First, we’ll <code>section</code> them off, then we’ll make a <code>container</code> for them. </p>\n<pre><code class='language-markup'><section class=\"section\">\r\n <div class=\"container\"></div>\r\n</section></code></pre>\n<p>Inside our <code>container</code>, we’ll put our <code>columns</code> parent div.</p>\n<pre><code class='language-markup'><section class=\"section\">\r\n <div class=\"container\">\r\n <div class=\"columns\"></div>\r\n </div>\r\n</section></code></pre>\n<p>Then we’ll put three <code>column</code> divs within as children. They’ll automatically divide into thirds of their viewport, whether viewed horizontally or vertically (on mobile). Bulma is inherently fully responsive.</p>\n<pre><code class='language-markup'><section class=\"section\">\r\n <div class=\"container\">\r\n <div class=\"columns\">\r\n <div class=\"column\">1</div>\r\n <div class=\"column\">2</div>\r\n <div class=\"column\">3</div>\r\n </div>\r\n </div>\r\n </section></code></pre>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508124305image3-1024x749.png\" alt=\"Bulma Example 3\" width=\"1024\" height=\"749\" class=\"aligncenter size-large wp-image-160649\" /></p>\n<p>Within each column, we’ll insert a Bulma <code>card</code>, whose <code>card-content</code> will be a <code>title</code> and <code>subtitle</code>, for the quote and the programmer who said the quote.</p>\n<pre><code class='language-markup'><div class=\"card\">\r\n <div class=\"card-content\">\r\n <h2 class=\"title\">\"Quote\"</h2> \r\n <h3 class=\"subtitle\">Programmer</h3>\r\n </div>\r\n</div></code></pre>\n<p>To make our like, dislike and share buttons, we’ll need a <code>card-footer</code>, then three <code>card-footer-items</code>, one for each <code>button</code> to live in. To color the buttons, we’ll add Bulma modifiers to turn them green (<code>is-success</code>), red (<code>is-danger</code>), and blue (<code>is-info</code>). Within the buttons, we’ll use Font Awesome’s classes to get a thumbs-up, thumbs-down and share icon.</p>\n<pre><code class='language-markup'><div class=\"card\">\r\n <div class=\"card-content\">\r\n <h2 class=\"title\">\"Quote\"</h2> \r\n <h3 class=\"subtitle\">Programmer</h3>\r\n </div>\r\n <footer class=\"card-footer\">\r\n <span class=\"card-footer-item\">\r\n <a href=\"#\" class=\"button is-success\">\r\n <i class=\"fa fa-thumbs-o-up\"></i>\r\n </a>\r\n </span>\r\n <span class=\"card-footer-item\"> \r\n <a href=\"#\" class=\"button is-danger\">\r\n <i class=\"fa fa-thumbs-o-down\"></i>\r\n </a>\r\n </span>\r\n <span class=\"card-footer-item\">\r\n <a href=\"#\" class=\"button is-info\">\r\n <i class=\"fa fa-retweet\"></i>\r\n </a>\r\n </span>\r\n </footer>\r\n</div></code></pre>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508124303image2.png\" alt=\"Bulma Example 2\" width=\"432\" height=\"282\" class=\"aligncenter size-full wp-image-160648\" /></p>\n<p>Now that we’ve successfully crafted one column, we can simply copy and paste that <strong>column’s</strong> code to make our three columns, and our site is ready.</p>\n<pre><code class='language-markup'><section class=\"section\"> \r\n <div class=\"container\"> \r\n <div class=\"columns\">\r\n\r\n <div class=\"column\">\r\n <div class=\"card\">\r\n <div class=\"card-content\">\r\n <h2 class=\"title\">\"Quote\"</h2> \r\n <h3 class=\"subtitle\">Programmer</h3>\r\n </div>\r\n <footer class=\"card-footer\">\r\n <span class=\"card-footer-item\">\r\n <a href=\"#\" class=\"button is-success\">\r\n <i class=\"fa fa-thumbs-o-up\"></i>\r\n </a>\r\n </span>\r\n <span class=\"card-footer-item\"> <!-- these will automatically resize just like columns -->\r\n <a href=\"#\" class=\"button is-danger\">\r\n <i class=\"fa fa-thumbs-o-down\"></i>\r\n </a>\r\n </span>\r\n <span class=\"card-footer-item\">\r\n <a href=\"#\" class=\"button is-info\">\r\n <i class=\"fa fa-retweet\"></i>\r\n </a>\r\n </span>\r\n </footer>\r\n </div>\r\n </div>\r\n\r\n <div class=\"column\">\r\n <div class=\"card\">\r\n <div class=\"card-content\">\r\n <h2 class=\"title\">\"Quote\"</h2>\r\n <h3 class=\"subtitle\">Programmer</h3>\r\n </div>\r\n <footer class=\"card-footer\">\r\n <span class=\"card-footer-item\">\r\n <a href=\"#\" class=\"button is-success\">\r\n <i class=\"fa fa-thumbs-o-up\"></i>\r\n </a>\r\n </span>\r\n <span class=\"card-footer-item\">\r\n <a href=\"#\" class=\"button is-danger\">\r\n <i class=\"fa fa-thumbs-o-down\"></i>\r\n </a>\r\n </span>\r\n <span class=\"card-footer-item\">\r\n <a href=\"#\" class=\"button is-info\">\r\n <i class=\"fa fa-retweet\"></i>\r\n </a>\r\n </span>\r\n </footer>\r\n </div>\r\n </div>\r\n\r\n <div class=\"column\">\r\n <div class=\"card\">\r\n <div class=\"card-content\">\r\n <h2 class=\"title\">\"Quote\"</h2>\r\n <h3 class=\"subtitle\">Programmer</h3>\r\n </div>\r\n <footer class=\"card-footer\">\r\n <span class=\"card-footer-item\">\r\n <a href=\"#\" class=\"button is-success\">\r\n <i class=\"fa fa-thumbs-o-up\"></i>\r\n </a>\r\n </span>\r\n <span class=\"card-footer-item\">\r\n <a href=\"#\" class=\"button is-danger\">\r\n <i class=\"fa fa-thumbs-o-down\"></i>\r\n </a>\r\n </span>\r\n <span class=\"card-footer-item\">\r\n <a href=\"#\" class=\"button is-info\">\r\n <i class=\"fa fa-retweet\"></i>\r\n </a>\r\n </span>\r\n </footer>\r\n </div>\r\n </div>\r\n\r\n </div>\r\n </div>\r\n</section></code></pre>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508124301image1-1024x590.png\" alt=\"Bulma Example 1\" width=\"1024\" height=\"590\" class=\"aligncenter size-large wp-image-160647\" /></p>\n<p>If you’re interested in learning more about Bulma, check out the <a href=\"http://bulma.io/made-with-bulma/?utm_source=sitepoint&utm_medium=article&utm_campaign=open_sourcecraft_bulma\">example sites</a> and <a href=\"http://bulma.io/documentation/overview/start/?utm_source=sitepoint&utm_medium=article&utm_campaign=open_sourcecraft_bulma\">documentation</a> on Bulma.io. And for more content like this, visit <a href=\"http://codepop.com/open-sourcecraft/?utm_source=sitepoint&utm_medium=article&utm_campaign=open_sourcecraft_bulma&utm_content=bottom\">Open SourceCraft</a>.</p>\n","protected":false},"excerpt":{"rendered":"<p>In this tutorial, we’ll be getting started with Bulma, a modern CSS Framework built on Flexbox. For best results, follow along with the above video by OpenSource Craft. If you want to learn why you should care about Bulma, check out this video.</p>\n<p>We’ll be building a Coding Quotes page, utilizing Bulma’s UI components including a Hero banner, Columns, Cards, Buttons and more.</p>\n","protected":false},"author":72589,"featured_media":160644,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[408,3768,6523],"tags":[11578,6985,11577],"_links":{"self":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/posts/160623"}],"collection":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/posts"}],"about":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/types/post"}],"author":[{"embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/users/72589"}],"replies":[{"embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/comments?post=160623"}],"version-history":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/posts/160623/revisions"}],"wp_featuredmedia":[{"embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/media/160644"}],"wp_attachment":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/media?parent=160623"}],"wp_term":[{"taxonomy":"category","embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/categories?post=160623"},{"taxonomy":"post_tag","embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/tags?post=160623"}],"curies":[{"name":"wp","href":"https://api.w.org/{rel}","templated":true}]}}
{"index":{"_index":"blogs","_id":160619,"_type":"default"}}
{"id":160619,"date":"2017-10-15T08:26:10","date_gmt":"2017-10-15T15:26:10","guid":{"rendered":"https://www.sitepoint.com/?p=160619"},"modified":"2017-10-15T08:26:10","modified_gmt":"2017-10-15T15:26:10","slug":"symfony-flex-paving-path-faster-better-symfony","status":"publish","type":"post","link":"https://www.sitepoint.com/symfony-flex-paving-path-faster-better-symfony/","title":{"rendered":"Symfony Flex: Paving the Path to a Faster, Better Symfony"},"content":{"rendered":"<p>Symfony Flex is a modern replacement for the Symfony Installer, and not the name of the next Symfony version. As the intro text says:</p>\n<blockquote>\n<p>Internally, Symfony Flex is a Composer plugin that modifies the behavior of the require and update commands. When installing or updating dependencies in a Flex-enabled application, Symfony can perform tasks before and after the execution of Composer tasks.</p>\n</blockquote>\n<p>The new Symfony will be called just Symfony 4, and while this tutorial will deal only with the Flex tool, it will mention some Symfony 4 upgrades as well.</p>\n\n<hr />\n<h2 id=\"stillunderdevelopment\">Still Under Development</h2>\n<p>Symfony Flex can be considered a <a href=\"https://www.sitepoint.com/re-introducing-composer/\">Composer</a> wrapper, in that it provides your Symfony project with additional options during installation and configuration. It was developed with simplicity in mind, and obviously heavily influenced by the user-friendliness of Laravel. Remember, Laravel got to its current level of popularity due to its ease of use and the low entry barrier it provides newcomers with, and Symfony wanted to emulate this.</p>\n<p>It should be noted that both Flex and Symfony 4 are still under development, slated for release somewhere at the end of November this year (2017). As such, some of the features mentioned in this post may have changed by the time you read it, but we’ll do our best to keep it up to date.</p>\n<p>Most notably, the use of a makefile and the make tool to build a project if <a href=\"https://www.sitepoint.com/re-introducing-symfony-console-cli-php-uninitiated/\">Symfony/Console</a> is unavailable is still up in the air, as it seems to not be working properly on some operating systems. Fabien recently <a href=\"https://www.surveymonkey.com/r/D857Q9F\">held a survey</a> around this, asking for the community’s suggestions to a replacement, and overwhelmingly, the community voted in favor of just making Symfony/Console required.</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/09/1507989122Screenshot-2017-10-14-15.51.00.png\" alt=\"Survey result\" /></p>\n<h2 id=\"whatsdifferent\">What’s Different?</h2>\n<p>Most notably, Flex respects the coming Symfony 4 updates which boil down to the following major changes:</p>\n<ul>\n<li>PHP 7+ is required</li>\n<li>all folders are optional. If your project isn’t using one, it doesn’t have to be there. This makes the directory tree much simpler and more readable. Additionally, often useless files like <code>.htaccess</code>, <code>LICENSE</code>, and <code>README</code> have been removed as well – a project which needs those can easily add them.</li>\n<li>there is no more <code>web</code> folder. Instead, there is the <code>public</code> folder, like in all other major frameworks. This consolidates user experience across ecosystems.</li>\n<li>temporary files go under <code>/var</code> in the root of the project folder, with the <code>/var/cache</code> subfolder reserved for long term cache, like merged class files for deploying apps as read-only artifacts</li>\n<li>source code goes under <code>/src</code>. No <code>/app</code>.</li>\n<li>configuration goes into <code>/config</code>.</li>\n<li>templates go into <code>/templates</code>.</li>\n<li>Flex will have its own Symfony-verified list of packages that are referenced by one and one alias alone. So executing <code>composer require cli</code> will actually trigger Flex, which will look in its list of packages, find the one tagged as <code>cli</code> (in this case, Symfony Console), and install it. These “official” packages are called recipes, and can be found <a href=\"https://github.com/symfony/recipes\">here</a>. To accept user-submitted recipes, a flag exists in Flex’s configuration which needs to be set to true: <code>composer config extra.symfony.allow-contrib true</code>. Those recipes can be found <a href=\"https://github.com/symfony/recipes-contrib\">here</a>. By officially endorsing some packages, Symfony is in many ways becoming as opinionated as Laravel. While this is bad in some ways, it’s very good in many more ways: a consolidated, opinionated way to build Symfony apps used by most people so that everyone is on the same page.</li>\n<li>bundle fragments no longer need to be custom-activated and added into a ton of files. Flex automates this, as well as their removal.</li>\n<li>instead of parameters in config files, Symfony 4 will be using environment variables like Laravel</li>\n</ul>\n<h2 id=\"bootstrapping\">Bootstrapping</h2>\n<p><em>As usual, we’ll assume you’re already running a healthy VM environment like <a href=\"http://www.sitepoint.com/quick-tip-get-homestead-vagrant-vm-running/\">Homestead Improved</a> so you can follow along.</em></p>\n<p>Okay, let’s get our hands dirty with an example app. All Symfony apps can now be started from the bare bones super-minimal Symfony Skeleton app: </p>\n<pre><code class=\"bash language-bash\"> composer create-project symfony/skeleton flexy\r\n</code></pre>\n<p>Notice the created directory structure.</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508072080Screenshot-2017-10-15-14.51.47.png\" alt=\"Directory structure\" /></p>\n<p>In <code>/public</code>, we no longer have <code>app.php</code> and <code>app_dev.php</code>, only the <code>index.php</code> file. The type of the environment (test / dev / prod) is now dictated with environment variables, and reads the configuration from the <code>/config</code> folder.</p>\n<p><em>Notice how the end of the installation process mentions that <code>make cache-warmup</code> was called, and that you can run <code>make serve</code>. This is where the new Symfony uses the “controversial” Makefile approach mentioned above. This might change.</em></p>\n<p>Out of the box, opening this skeleton in the browser will throw an error because no routes have been defined yet. Let’s fix this.</p>\n<pre><code class=\"yaml language-yaml\">index:\r\n path: /\r\n defaults: { _controller: 'App\\Controller\\DefaultController::index' }\r\n</code></pre>\n<blockquote>\n<p><code>config/routes.yaml</code></p>\n</blockquote>\n<p>We’ll need to create this controller and its <code>index</code> action:</p>\n<pre><code class=\"php language-php\"><?php\r\n\r\nnamespace App\\Controller;\r\nuse Symfony\\Component\\HttpFoundation\\Response;\r\n\r\nclass DefaultController\r\n{\r\n public function index()\r\n {\r\n return new Response('Hello');\r\n }\r\n}\r\n</code></pre>\n<p>This will produce a simple Hello screen, like so:</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508075063Screenshot-2017-10-15-15.44.09.png\" alt=\"Hello Symfony\" /></p>\n<h3 id=\"executionpermissions\">Execution Permissions</h3>\n<p>If you try to install a binary like the Symfony/Console with <code>composer req cli</code>, you might run into the following problem:</p>\n<pre><code class=\"bash language-bash\">~ bin/console\r\n-bash: bin/console: Permission denied\r\n</code></pre>\n<p>This is a known hiccup when using virtual machines, and can be easily fixed by either:</p>\n<ul>\n<li>running the console with <code>php bin/console</code> instead of running it directly, or</li>\n<li>adding the “execute” permission to the file on the host machine (not from within the virtual machine), by executing: <code>chmod +x bin/console</code>. This will allow the direct execution of <code>bin/console</code> from within the VM then.</li>\n</ul>\n<h2 id=\"addingbundles\">Adding Bundles</h2>\n<p>That “Hello” view we built is kind of naked. Let’s add some templates into the mix.</p>\n<pre><code class=\"bash language-bash\">composer req template\r\n</code></pre>\n<p>We can use <code>template</code>, <code>twig</code>, <code>templates</code>, or <code>templating</code> here, as defined in the <a href=\"https://github.com/symfony/recipes/blob/master/symfony/twig-bundle/3.3/manifest.json\">Twig recipe’s aliases</a>.</p>\n<p>The Symfony 4 / Flex approach will automatically activate this bundle for us and set up a folder (<code>/templates</code>) with a <code>base</code> layout view, as well as a configuration file (<code>config/packages/twig.yaml</code>).</p>\n<p>We are now free to define a view for our Hello route:</p>\n<pre><code class=\"php language-php\">{% extends '../base.html.twig' %}\r\n\r\n{% block body %}\r\n {{ greeting }}\r\n{% endblock %}\r\n</code></pre>\n<blockquote>\n<p><code>/templates/default/index.html.twig</code></p>\n</blockquote>\n<p>Now we can modify the controller to return this instead of the plain text response:</p>\n<pre><code class=\"php language-php\"><?php\r\n\r\nnamespace App\\Controller;\r\n\r\nuse Symfony\\Bundle\\FrameworkBundle\\Controller\\Controller;\r\n\r\nclass DefaultController extends Controller\r\n{\r\n public function index()\r\n {\r\n return $this->render('default/index.html.twig', ['greeting' => 'hello']);\r\n }\r\n}\r\n</code></pre>\n<p>Notice how we had to extend the <code>FrameworkBundle</code>‘s controller to get access to the <code>render</code> method, but that was about all the added configuration we had to do. Our hello route is now way cooler.</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508076507Screenshot-2017-10-15-16.06.46.png\" alt=\"Screenshot of templated view\" /></p>\n<h3 id=\"bigbundles\">Big Bundles</h3>\n<p>Now let’s try adding in a big bundle – one that includes several others. The <code>admin</code> bundle for creating backends is a good option. Besides, it’s one the Symfony team decided to officially endorse, and it pulls in the <code>orm</code> recipe, which refers to Doctrine – another Symfony recommendation (can you see the opinionatedness in action?)</p>\n<pre><code class=\"bash language-bash\">composer req admin\r\n</code></pre>\n<p>We’ll need to create an entity before we can use the admin bundle. For that, we need a database. Create a new database and user. This process should be fine:</p>\n<pre><code class=\"bash language-bash\">mysql -u homestead -psecret\r\ncreate database flexy character set utf8mb4 collate utf8mb4_unicode_ci;\r\n</code></pre>\n<p>Feel free to create a database specific user too if you feel it’s necessary. Then, modify the <code>.env</code> file to respect this:</p>\n<pre><code class=\"env language-env\">DATABASE_URL=\"mysql://homestead:[email protected]:3306/flexy?charset=utf8mb4&serverVersion=5.7\"\r\n</code></pre>\n<p>Finally, let’s create an entity. Suppose we’re making a site that lets users make submissions to the site – like Reddit, links to submit for example. We’ll have an entity called “Submission”, like so:</p>\n<pre><code class=\"php language-php\"><?php\r\n\r\n\r\nnamespace App\\Entity;\r\nuse Doctrine\\ORM\\Mapping as ORM;\r\n\r\n/**\r\n * Class Submission\r\n * @package App\\Entity\r\n *\r\n * @ORM\\Entity\r\n * @ORM\\Table(name=\"submission\")\r\n */\r\nclass Submission\r\n{\r\n /**\r\n * @ORM\\Column(type=\"integer\")\r\n * @ORM\\Id\r\n * @ORM\\GeneratedValue(strategy=\"AUTO\")\r\n */\r\n public $id;\r\n\r\n /**\r\n * @ORM\\Column(type=\"string\", length=255)\r\n */\r\n public $name;\r\n\r\n /**\r\n * @ORM\\Column(type=\"string\", length=255)\r\n */\r\n public $url;\r\n\r\n /**\r\n * @ORM\\Column(type=\"text\")\r\n */\r\n public $description;\r\n}\r\n</code></pre>\n<p>The entity needs to be registered in the <code>config/packages/easy_admin.yml</code> file:</p>\n<pre><code class=\"yaml language-yaml\">easy_admin:\r\n entities:\r\n - App\\Entity\\Submission\r\n</code></pre>\n<p>Now we’ll have Doctrine create this table for us.</p>\n<pre><code class=\"bash language-bash\">bin/console doctrine:schema:update --force\r\n</code></pre>\n<p>Note that you can also have Doctrine create the database as well if it doesn’t exist. Look into <code>doctrine:database:create</code> for that functionality.</p>\n<p>If we now visit the <code>/admin</code> URL of our app, we should see something like this:</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508077802Screenshot-2017-10-15-16.29.19.png\" alt=\"Easy Admin Bundle Back End Screen\" /></p>\n<p>Adding submissions should now work like a charm:</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508077905Screenshot-2017-10-15-16.31.31.png\" alt=\"A submission was added\" /></p>\n<h3 id=\"unofficialbundles\">Unofficial Bundles</h3>\n<p>What about bundles that aren’t officially backed by Symfony?</p>\n<p>For that, we need to flip a Composer flag’s switch.</p>\n<pre><code class=\"bash language-bash\">composer config extra.symfony.allow-contrib true\r\n</code></pre>\n<p>This will allow for pulling of recipes from <a href=\"https://github.com/symfony/recipes-contrib\">this repository</a> as well. Let’s say we want to make our submissions have <code>uuid</code> for ID instead of a simple auto-incrementing integer. We can use <a href=\"https://github.com/symfony/recipes-contrib/tree/master/ramsey/uuid-doctrine/1.3\">Ramsey’s UUID-Doctrine</a> bundle for that. When requesting contrib recipes, they typically don’t have aliases and have to be referenced in full, like regular packages.</p>\n<pre><code class=\"bash language-bash\">composer req ramsey/uuid-doctrine\r\n</code></pre>\n<p>Since this is a community contributed package, Symfony will throw a warning at you once it’s done downloading it.</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508078537Screenshot-2017-10-15-16.37.02.png\" alt=\"A warning about the contrib recipe\" /></p>\n<p><em>Note: The contrib repo is a great filter of dead bundles and packages – every bundle/package developer who cares about their work will have moved it there, so you can be sure that the development on the missing ones has stagnated.</em></p>\n<p>Once the package has been installed, we can use it in our project.</p>\n<p>First, we need to tell Doctrine that it’s now available (something the recipe should do by itself, in my opinion – not automated enough just yet!):</p>\n<pre><code>doctrine:\r\n dbal:\r\n url: '%env(DATABASE_URL)%'\r\n types:\r\n uuid: Ramsey\\Uuid\\Doctrine\\UuidType\r\n orm:\r\n ...\r\n</code></pre>\n<blockquote>\n<p><code>config/packages/doctrine.yaml</code></p>\n</blockquote>\n<p>Next, we change the Submission entity to use this type on its <code>id</code> attribute:</p>\n<pre><code class=\"php language-php\">...\r\nclass Submission\r\n{\r\n /**\r\n * @var \\Ramsey\\Uuid\\Uuid\r\n *\r\n * @ORM\\Id\r\n * @ORM\\Column(type=\"uuid\", unique=true)\r\n * @ORM\\GeneratedValue(strategy=\"CUSTOM\")\r\n * @ORM\\CustomIdGenerator(class=\"Ramsey\\Uuid\\Doctrine\\UuidGenerator\")\r\n */\r\n public $id;\r\n...\r\n</code></pre>\n<p>Now let’s update the database and clear current entities:</p>\n<pre><code class=\"bash language-bash\">bin/console doctrine:schema:drop --force\r\nbin/console doctrine:schema:update --force\r\n</code></pre>\n<p>Finally, let’s try re-visiting <code>/admin</code> and adding a new entity.</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508079570Screenshot-2017-10-15-16.59.07.png\" alt=\"New entity added\" /></p>\n<p>Sure enough, our new entity has a UUID for a primary key.</p>\n<p><em>Note: it is recommended to use another type when using UUID for primary keys in InnoDB type databases, but for the sake of brevity we used the default. Full instructions <a href=\"https://github.com/ramsey/uuid-doctrine\">here</a>.</em></p>\n<h3 id=\"addingthirdpartytools\">Adding Third Party Tools</h3>\n<p>Other third party tools can be used just like before – only they won’t be auto-configurable by Flex. You’ll have to register them manually and remove them in the same way. It is therefore recommended you move any package that needs extra configuration to work smoothly with Symfony into the <code>contrib</code> recipes repo, so that others may benefit from the smoother Flex workflow.</p>\n<h2 id=\"conclusion\">Conclusion</h2>\n<p>Symfony Flex is the modern way to install and manage Symfony apps, and it’s the red carpet towards the door of Symfony 4. Needless to say, we’re very excited about Symfony’s most recent foray into modern development and the field of high-DX, and we’ll be keeping a close eye on it. We hope you found this introduction useful!</p>\n<p>We didn’t benchmark this final result with another framework purely because it makes no sense when you consider the possible optimizations you can do, but also because we’ve got a performance month coming up (all of November) during which we’ll devour all sorts of performance related issues and go through a whole set of techniques you’ll be able to apply to your projects – no matter the framework or app type. Stay tuned!</p>\n","protected":false},"excerpt":{"rendered":"<p>Symfony Flex is a modern replacement for the Symfony Installer, and not the name of the next Symfony version. As the intro text says:</p>\n<blockquote>\n<p>Internally, Symfony Flex is a Composer plugin that modifies the behavior of the require and update commands. When installing or updating dependencies in a Flex-enabled application, Symfony can perform tasks before and after the execution of Composer tasks.</p>\n</blockquote>\n<p>The new Symfony will be called just Symfony 4, and while this tutorial will deal only with the Flex tool, it will mention some Symfony 4 upgrades as well.</p>\n<hr />\n<h2 id=\"stillunderdevelopment\">Still Under Development</h2>\n<p>Symfony Flex can be considered a <a href=\"https://www.sitepoint.com/re-introducing-composer/\">Composer</a> wrapper, in that it provides your Symfony project with additional options during installation and configuration. It was developed with simplicity in mind, and obviously heavily influenced by the user-friendliness of Laravel. Remember, Laravel got to its current level of popularity due to its ease of use and the low entry barrier it provides newcomers with, and Symfony wanted to emulate this.</p>\n<p>It should be noted that both Flex and Symfony 4 are still under development, slated for release somewhere at the end of November this year (2017). As such, some of the features mentioned in this post may have changed by the time you read it, but we’ll do our best to keep it up to date.</p>\n<p>Most notably, the use of a makefile and the make tool to build a project if <a href=\"https://www.sitepoint.com/re-introducing-symfony-console-cli-php-uninitiated/\">Symfony/Console</a> is unavailable is still up in the air, as it seems to not be working properly on some operating systems. Fabien recently <a href=\"https://www.surveymonkey.com/r/D857Q9F\">held a survey</a> around this, asking for the community’s suggestions to a replacement, and overwhelmingly, the community voted in favor of just making Symfony/Console required.</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/09/1507989122Screenshot-2017-10-14-15.51.00.png\" alt=\"Survey result\" /></p>\n<h2 id=\"whatsdifferent\">What’s Different?</h2>\n<p>Most notably, Flex respects the coming Symfony 4 updates which boil down to the following major changes:</p>\n<ul>\n<li>PHP 7+ is required</li>\n<li>all folders are optional. If your project isn’t using one, it doesn’t have to be there. This makes the directory tree much simpler and more readable. Additionally, often useless files like <code>.htaccess</code>, <code>LICENSE</code>, and <code>README</code> have been removed as well – a project which needs those can easily add them.</li>\n<li>there is no more <code>web</code> folder. Instead, there is the <code>public</code> folder, like in all other major frameworks. This consolidates user experience across ecosystems.</li>\n<li>temporary files go under <code>/var</code> in the root of the project folder, with the <code>/var/cache</code> subfolder reserved for long term cache, like merged class files for deploying apps as read-only artifacts</li>\n<li>source code goes under <code>/src</code>. No <code>/app</code>.</li>\n<li>configuration goes into <code>/config</code>.</li>\n<li>templates go into <code>/templates</code>.</li>\n<li>Flex will have its own Symfony-verified list of packages that are referenced by one and one alias alone. So executing <code>composer require cli</code> will actually trigger Flex, which will look in its list of packages, find the one tagged as <code>cli</code> (in this case, Symfony Console), and install it. These “official” packages are called recipes, and can be found <a href=\"https://github.com/symfony/recipes\">here</a>. To accept user-submitted recipes, a flag exists in Flex’s configuration which needs to be set to true: <code>composer config extra.symfony.allow-contrib true</code>. Those recipes can be found <a href=\"https://github.com/symfony/recipes-contrib\">here</a>. By officially endorsing some packages, Symfony is in many ways becoming as opinionated as Laravel. While this is bad in some ways, it’s very good in many more ways: a consolidated, opinionated way to build Symfony apps used by most people so that everyone is on the same page.</li>\n<li>bundle fragments no longer need to be custom-activated and added into a ton of files. Flex automates this, as well as their removal.</li>\n<li>instead of parameters in config files, Symfony 4 will be using environment variables like Laravel</li>\n</ul>\n<h2 id=\"bootstrapping\">Bootstrapping</h2>\n<p><em>As usual, we’ll assume you’re already running a healthy VM environment like <a href=\"http://www.sitepoint.com/quick-tip-get-homestead-vagrant-vm-running/\">Homestead Improved</a> so you can follow along.</em></p>\n<p>Okay, let’s get our hands dirty with an example app. All Symfony apps can now be started from the bare bones super-minimal Symfony Skeleton app: </p>\n<pre><code class=\"bash language-bash\"> composer create-project symfony/skeleton flexy\r\n</code></pre>\n<p>Notice the created directory structure.</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508072080Screenshot-2017-10-15-14.51.47.png\" alt=\"Directory structure\" /></p>\n<p>In <code>/public</code>, we no longer have <code>app.php</code> and <code>app_dev.php</code>, only the <code>index.php</code> file. The type of the environment (test / dev / prod) is now dictated with environment variables, and reads the configuration from the <code>/config</code> folder.</p>\n<p><em>Notice how the end of the installation process mentions that <code>make cache-warmup</code> was called, and that you can run <code>make serve</code>. This is where the new Symfony uses the “controversial” Makefile approach mentioned above. This might change.</em></p>\n<p>Out of the box, opening this skeleton in the browser will throw an error because no routes have been defined yet. Let’s fix this.</p>\n<pre><code class=\"yaml language-yaml\">index:\r\n path: /\r\n defaults: { _controller: 'App\\Controller\\DefaultController::index' }\r\n</code></pre>\n<blockquote>\n<p><code>config/routes.yaml</code></p>\n</blockquote>\n<p>We’ll need to create this controller and its <code>index</code> action:</p>\n<pre><code class=\"php language-php\"><?php\r\n\r\nnamespace App\\Controller;\r\nuse Symfony\\Component\\HttpFoundation\\Response;\r\n\r\nclass DefaultController\r\n{\r\n public function index()\r\n {\r\n return new Response('Hello');\r\n }\r\n}\r\n</code></pre>\n<p>This will produce a simple Hello screen, like so:</p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1508075063Screenshot-2017-10-15-15.44.09.png\" alt=\"Hello Symfony\" /></p>\n<h3 id=\"executionpermissions\">Execution Permissions</h3>\n<p>If you try to install a binary like the Symfony/Console with <code>composer req cli</code>, you might run into the following problem:</p>\n<pre><code class=\"bash language-bash\">~ bin/console\r\n-bash: bin/console: Permission denied\r\n</code></pre>\n<p>This is a known hiccup when using virtual machines, and can be easily fixed by either:</p>\n<ul>\n<li>running the console with <code>php bin/console</code> instead of running it directly, or</li>\n<li>adding the “execute” permission to the file on the host machine (not from within the virtual machine), by executing: <code>chmod +x bin/console</code>. This will allow the direct execution of <code>bin/console</code> from within the VM then.</li>\n</ul>\n","protected":false},"author":71392,"featured_media":92633,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[7888,206,13,246,37,3924],"tags":[5946,4333,2023,9760,3566,11576],"_links":{"self":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/posts/160619"}],"collection":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/posts"}],"about":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/types/post"}],"author":[{"embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/users/71392"}],"replies":[{"embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/comments?post=160619"}],"version-history":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/posts/160619/revisions"}],"wp_featuredmedia":[{"embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/media/92633"}],"wp_attachment":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/media?parent=160619"}],"wp_term":[{"taxonomy":"category","embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/categories?post=160619"},{"taxonomy":"post_tag","embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/tags?post=160619"}],"curies":[{"name":"wp","href":"https://api.w.org/{rel}","templated":true}]}}
{"index":{"_index":"blogs","_id":160588,"_type":"default"}}
{"id":160588,"date":"2017-10-13T09:00:07","date_gmt":"2017-10-13T16:00:07","guid":{"rendered":"https://www.sitepoint.com/?p=160588"},"modified":"2017-10-13T01:25:08","modified_gmt":"2017-10-13T08:25:08","slug":"writing-beautiful-sass","status":"publish","type":"post","link":"https://www.sitepoint.com/writing-beautiful-sass/","title":{"rendered":"How to Write Beautiful Sass"},"content":{"rendered":"<p><em>The following is a short extract from our book, <a href=\"https://www.sitepoint.com/premium/books/jump-start-sass\">Jump Start Sass</a>, written by Hugo Giraudel and Miriam Suzanne. It’s the ultimate beginner’s guide to Sass. SitePoint Premium members get access with their membership, or you can buy a copy in stores worldwide.</em></p>\n<p>Clean, beautiful code should be a goal in every project. If other developers need to make a change, they should be able to read what is there and understand it. Readable code is the core of maintainability, and the first step towards readable code is a good <strong>linter</strong>. Like a good spell-checker, the linter should catch all your small typos and formatting mistakes, so it’s not left to others to do so. It’s the first line of defense before a good code review with other developers.</p>\n<p>There are several great linters for Sass: <a class=\"ulink\" href=\"https://github.com/brigade/scss-lint\">scss-lint</a> is a Ruby gem, and the newer <a class=\"ulink\" href=\"https://github.com/sasstools/sass-lint\">sasslint</a> and <a class=\"ulink\" href=\"http://stylelint.io/\">stylelint</a>, which are npm packages for Node. Both allow you to configure linting rules for your project, such as maximum nesting levels, leading zeros on decimals, and organization of properties in a block. You can even create your own rules as needed.</p>\n<p><a class=\"ulink\" href=\"http://sass-guidelin.es/\">Sass Guidelines</a> are handy for organizing your project, setting up your linters, establishing naming conventions, and so on. Written by Hugo, it’s an opinionated styleguide for your code; it might not all work for you, but it’s a great place to start.</p>\n<p>If you’re using Sass variables, functions, and mixins, it’s recommended that you document how they work. Toolkit authors will find it particularly important, but anyone who has extensive tooling built into their projects should also consider documentation for their team. Another great tool from Hugo is <a class=\"ulink\" href=\"http://sassdoc.com\">SassDoc</a>, an npm package that parses your Sass comments and generates a beautiful static site with your documentation.</p>\n<p>Here’s the SassDoc comment for our <code class=\"literal\">tint(..)</code> function in Accoutrement-Colors. It starts with a general description, and then explicitly documents each parameter and the expected return:</p>\n<pre><code class=\"language-scss\"> /// Mix a color with `white` to get a lighter tint.\r\n///\r\n/// @param {String | list} $color -\r\n/// The name of a color in your palette,\r\n/// with optional adjustments in the form of `(<function-name>:<args>)`.\r\n/// @param {Percentage} $percentage -\r\n/// The percentage of white to mix in.\r\n/// Higher percentages will result in a lighter tint.\r\n///\r\n/// @return {Color} -\r\n/// A calculated css-ready color-value based on your global color palette.\r\n@function tint(\r\n $color,\r\n $percentage\r\n) {\r\n /* … */\r\n}\r\n</code></pre>\n<p>Using the default theme (from which there are several to choose, or you can design your own), SassDoc converts that comment into a static website, as shown below. </p>\n<p><img src=\"https://www.sitepoint.com/wp-content/uploads/2017/10/1507827731sassdoc-output.png\" alt=\"\" width=\"600\" height=\"335\" class=\"aligncenter size-full wp-image-160589\" /></p>\n<p>Testing is also important if you are doing anything complex with functions or mixins. It’s a good way to ensure your code won’t break any time you make adjustments, but it can also be helpful in developing new features. If you write the tests first, you’ll know exactly if the feature works correctly when your tests pass!</p>\n<p><a class=\"ulink\" href=\"http://oddbird.net/true/\">True</a> is a unit-testing toolkit from yours truly, written in pure Sass so that it works anywhere Sass is compiled. The core testing happens in assertion functions: <code class=\"literal\">assert-equal(..)</code>, <code class=\"literal\">assert-unequal(..)</code>, <code class=\"literal\">assert-true(..)</code>, and <code class=\"literal\">assert-false(..)</code>. These are organized into tests, and can be grouped in test modules. Here’s an example of True testing our<br />\n <code class=\"literal\">tint(..)</code> function:</p>\n<pre><code class=\"language-scss\">@include test-module('Tint [function]') {\r\n @include test('Adjusts the tint of a color') {\r\n @include assert-equal(\r\n tint('primary', 25%),\r\n mix(#fff, color('primary'), 25%),\r\n 'Returns a color mixed with white at a given weight.');\r\n }\r\n}\r\n</code></pre>\n<p>When compiled, True will output CSS comments with detailed results, and warn you in the console if any tests fail:</p>\n<pre class=\"language-css\">/* # Module: Tint [function] */\r\n/* ------------------------- */\r\n/* Test: Adjusts the tint of a color */\r\n/* ✔ Returns a color mixed with white at a given weight. */\r\n\r\n/* … */\r\n\r\n/* # SUMMARY ---------- */\r\n/* 16 Tests: */\r\n/* - 14 Passed */\r\n/* - 0 Failed */\r\n/* - 2 Output to CSS */\r\n/* -------------------- */\r\n</pre>\n<p>What does it mean that two tests were “output to CSS” in this example? Those tests aren’t shown, but they are testing mixin output. Using pure CSS, True can only confirm the results of function tests, so mixin tests are simply output to the CSS where they can be compared manually (gross) or with a CSS parser (better!). To make that easy, True integrates with JavaScript test runners such as <a class=\"ulink\" href=\"https://mochajs.org/\">Mocha</a>, and has a Ruby command line interface written by <a class=\"ulink\" href=\"https://twitter.com/jetviper21\">Scott Davis</a>. Either one will parse the CSS output completely, including the output from mixins, and give you full results for both function and mixin tests:</p>\n<pre><code class=\"bash language-bash\">Luminance [function]\r\n ✓ Returns luminance of a color\r\n\r\nContrast Ratio [function]\r\n ✓ Returns contrast ratio between two colors\r\n\r\nContrast [function]\r\n ✓ Dark on light\r\n ✓ Light on dark\r\n ✓ Default light fallback\r\n ✓ Default dark fallback\r\n ✓ Multiple contrast options\r\n\r\ncontrasted [mixin]\r\n ✓ Dark on light\r\n ✓ Light on dark\r\n\r\nTint [function]\r\n ✓ Adjusts the tint of a color\r\n\r\nShade [function]\r\n ✓ Adjusts the shade of a color\r\n\r\nColor [function]\r\n ✓ Named color\r\n ✓ Referenced color\r\n ✓ Adjusted color\r\n ✓ Complex nesting of colors\r\n ✓ Multiple adjustment function arguments\r\n\r\n\r\n16 passing (11ms)\r\n</code><code></code></pre>\n","protected":false},"excerpt":{"rendered":"<p><em>The following is a short extract from our book, <a href=\"https://www.sitepoint.com/premium/books/jump-start-sass\">Jump Start Sass</a>, written by Hugo Giraudel and Miriam Suzanne. It’s the ultimate beginner’s guide to Sass. SitePoint Premium members get access with their membership, or you can buy a copy in stores worldwide.</em></p>\n<p>Clean, beautiful code should be a goal in every project. If other developers need to make a change, they should be able to read what is there and understand it. Readable code is the core of maintainability, and the first step towards readable code is a good <strong>linter</strong>. Like a good spell-checker, the linter should catch all your small typos and formatting mistakes, so it’s not left to others to do so. It’s the first line of defense before a good code review with other developers.</p>\n<p>There are several great linters for Sass: <a class=\"ulink\" href=\"https://github.com/brigade/scss-lint\">scss-lint</a> is a Ruby gem, and the newer <a class=\"ulink\" href=\"https://github.com/sasstools/sass-lint\">sasslint</a> and <a class=\"ulink\" href=\"http://stylelint.io/\">stylelint</a>, which are npm packages for Node. Both allow you to configure linting rules for your project, such as maximum nesting levels, leading zeros on decimals, and organization of properties in a block. You can even create your own rules as needed.</p>\n<p><a class=\"ulink\" href=\"http://sass-guidelin.es/\">Sass Guidelines</a> are handy for organizing your project, setting up your linters, establishing naming conventions, and so on. Written by Hugo, it’s an opinionated styleguide for your code; it might not all work for you, but it’s a great place to start.</p>\n<p>If you’re using Sass variables, functions, and mixins, it’s recommended that you document how they work. Toolkit authors will find it particularly important, but anyone who has extensive tooling built into their projects should also consider documentation for their team. Another great tool from Hugo is <a class=\"ulink\" href=\"http://sassdoc.com\">SassDoc</a>, an npm package that parses your Sass comments and generates a beautiful static site with your documentation.</p>\n<p>Here’s the SassDoc comment for our <code class=\"literal\">tint(..)</code> function in Accoutrement-Colors. It starts with a general description, and then explicitly documents each parameter and the expected return:</p>\n<pre><code class=\"language-scss\"> /// Mix a color with `white` to get a lighter tint.\r\n///\r\n/// @param {String | list} $color -\r\n/// The name of a color in your palette,\r\n/// with optional adjustments in the form of `(<function-name>:<args>)`.\r\n/// @param {Percentage} $percentage -\r\n/// The percentage of white to mix in.\r\n/// Higher percentages will result in a lighter tint.\r\n///\r\n/// @return {Color} -\r\n/// A calculated css-ready color-value based on your global color palette.\r\n@function tint(\r\n $color,\r\n $percentage\r\n) {\r\n /* … */\r\n}\r\n</code></pre>\n<p>Using the default theme (from which there are several to choose, or you can design your own), SassDoc converts that comment into a static website, as shown below. </p>\n","protected":false},"author":72289,"featured_media":160575,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[408,6523,3938],"tags":[9773,8151,9769,3989],"_links":{"self":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/posts/160588"}],"collection":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/posts"}],"about":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/types/post"}],"author":[{"embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/users/72289"}],"replies":[{"embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/comments?post=160588"}],"version-history":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/posts/160588/revisions"}],"wp_featuredmedia":[{"embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/media/160575"}],"wp_attachment":[{"href":"https://www.sitepoint.com/wp-json/wp/v2/media?parent=160588"}],"wp_term":[{"taxonomy":"category","embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/categories?post=160588"},{"taxonomy":"post_tag","embeddable":true,"href":"https://www.sitepoint.com/wp-json/wp/v2/tags?post=160588"}],"curies":[{"name":"wp","href":"https://api.w.org/{rel}","templated":true}]}}