Tag: from

Blocking Third-Party Hands from the Cookie Jar

Third-party cookies are set on your computer from domains other than the one that you’re actually on right now. For example, if I log into css-tricks.com, I’ll get a cookie from css-tricks.com that handles my authentication. But css-tricks.com might also load an image from some other site. A common tactic in online advertising is to render a “tracking pixel” image (well named, right?) that is used to track advertising impressions. That request to another site for the image (say, ad.doubleclick.com) also can set a cookie.

Eric Lawrence explains the issue:

The tracking pixel’s cookie is called a third party cookie because it was set by a domain unrelated to the page itself.

If you later visit B.textslashplain.com, which also contains a tracking pixel from ad.doubleclick.net, the tracking pixel’s cookie set on your visit to A.example.com is sent to ad.doubleclick.net, and now that tracker knows that you’ve visited both sites. As you browse more and more sites that contain a tracking pixel from the same provider, that provider can build up a very complete profile of the sites you like to visit, and use that information to target ads to you, sell the data to a data aggregation company, etc.

But times are a changin’. Eric goes on to explain the browser landscape:

The default stuff is the big deal, because all browsers offer some way to block third-party cookies. But of course, nobody actually does it. Jeremy:

It’s hard to believe that we ever allowed third-party cookies and scripts in the first place. Between them, they’re responsible for the worst ills of the World Wide Web.

2019 is the year we apparently reached the breaking point.

The post Blocking Third-Party Hands from the Cookie Jar appeared first on CSS-Tricks.

CSS-Tricks

, , , ,

Get Geographic Information from an IP Address for Free

Say you need to know what country someone visiting your website is from, because you have an internationalized site and display different things based on that country. You could ask the user. You might want to have that functionality anyway to make sure your visitors have control, but surely they will appreciate it just being correct out of the gate, to the best of your ability.

There are no native web technologies that have this information. JavaScript has geolocation, but users would have to approve that, and even then you’d have to use some library to convert the coordinates into a more usable country. Even back-end languages, which have access to the IP address in a way that JavaScript doesn’t, don’t just automatically know the country of origin.

CANADA. I JUST WANNA KNOW IF THEY ARE FROM CANADA OR NOT.

You have to ask some kind of service that knows this. The IP Geolocation API is that service, and it’s free.

You perform a GET against the API. You can do it right in the browser if you want to test it:

https://api.ipgeolocationapi.com/geolocate/184.149.48.32

But you don’t just get the country. You get a whole pile of information you might need to use. I happen to be sitting in Canada and this is what I get for my IP:

{     "continent":"North America",    "address_format":"{{recipient}}\n{{street}}\n{{city}} {{region_short}} {{postalcode}}\n{{country}}",    "alpha2":"CA",    "alpha3":"CAN",    "country_code":"1",    "international_prefix":"011",    "ioc":"CAN",    "gec":"CA",    "name":"Canada",    "national_destination_code_lengths":[        3    ],    "national_number_lengths":[        10    ],    "national_prefix":"1",    "number":"124",    "region":"Americas",    "subregion":"Northern America",    "world_region":"AMER",    "un_locode":"CA",    "nationality":"Canadian",    "postal_code":true,    "unofficial_names":[        "Canada",       "Kanada",       "Canadá",       "カナダ"    ],    "languages_official":[        "en",       "fr"    ],    "languages_spoken":[        "en",       "fr"    ],    "geo":{        "latitude":56.130366,       "latitude_dec":"62.832908630371094",       "longitude":-106.346771,       "longitude_dec":"-95.91332244873047",       "max_latitude":83.6381,       "max_longitude":-50.9766,       "min_latitude":41.6765559,       "min_longitude":-141.00187,       "bounds":{           "northeast":{              "lat":83.6381,             "lng":-50.9766          },          "southwest":{              "lat":41.6765559,             "lng":-141.00187          }       }    },    "currency_code":"CAD",    "start_of_week":"sunday" }

With that information, I could easily decide to redirect to the Canadian version of my website, if I have one, or show prices in CAD, or offer a French translation, or whatever else I can think of.

Say you were in PHP. You could get the IP like…

function getUserIpAddr() {   if (!empty($  _SERVER['HTTP_CLIENT_IP'])) {     $  ip = $  _SERVER['HTTP_CLIENT_IP'];   } elseif (!empty($  _SERVER['HTTP_X_FORWARDED_FOR'])) {     $  ip = $  _SERVER['HTTP_X_FORWARDED_FOR'];   } else {     $  ip = $  _SERVER['REMOTE_ADDR'];   }   return $  ip; }

The cURL to get the information:

$  url = "https://api.ipgeolocationapi.com/geolocate/184.149.48.32";  $  ch = curl_init();   curl_setopt($  ch, CURLOPT_RETURNTRANSFER, 1);  curl_setopt($  ch, CURLOPT_URL, $  url);  $  result = curl_exec($  ch); 

It comes back as JSON, so:

$  json = json_decode($  result);

And then $ json->{'name'}; will be “Canada” if I’m in Canada.

So I can do like:

if ($  json->{'name'} == "Canada") {   // serve index-ca.php } else {   // server index.php }

The post Get Geographic Information from an IP Address for Free appeared first on CSS-Tricks.

CSS-Tricks

, , , ,
[Top]

Random Notes from a JAMstack Roundtable

I hosted a JAMstack roundtable discussion at Web Unleashed this past weekend. Just a few random notes from that experience.

  • I was surprised at first that there really is confusion that the “M” in Jamstack stands for “Markdown” (the language that compiles to HTML) rather than “Markup” (the “M” in HTML, sometimes used interchangeably with HTML). It came up as legit confusion. Answer: Markdown isn’t required for JAMstack. The confusion comes from the idea that Markdown often goes hand-in-hand with static site generators which go hand-in-hand with JAMstack.
  • It occurred to me for the first time that every single site that is hosted on Netlify or GitHub Pages or an S3 bucket (“static hosting”) is JAMstack. SHAMstack, indeed! :). The static hosting (SH) part of JAMstack is, perhaps, the most important aspect.
  • A website that is a single index.html file with <div id="root"> and a bundle of JavaScript that client-site renders the rest of everything can be JAMstack. Assuming the data it needs is either baked in or coming from an API on some other server that isn’t the one that hosts that index.html file, it’s JAMstack.
  • There is a difference between technically JAMstack and spiritually JAMstack. The above is perhaps more technically and less spiritually. The latter wants you to pre-render more of the site than nothing.
  • Pre-rendering is nice because: it’s fast, it can be CDN-hosted, it’s secure, and it’s SEO-friendly. A lot of frameworks give it to you as part of what they do, so you might as well take advantage. Pre-rendering doesn’t mean static, JavaScript can still load and get fancy.
  • There is no denying that Static Site Generators and JAMstack are BFF. But JAMstack wants you to think bigger. What if you can’t render everything because you have 50,000 product pages and generation is too slow or otherwise impractical? No problem, you can prerender other pages but just a shell for the product pages and hit an API for product page data as needed. What if some pages just absolutely can’t be statically hosted? No problem, you can proxy the ones that can to a static server and leave the rest alone. Want to go all-in on the static hosting, but need servers for certain functionality? Consider serverless functions, which are sort of like the backend spiritual partner to static hosting.
  • People really want to know why. Why bother with this stuff at all? If you can build a site that does all the stuff you need with WordPress, why not just do that? I ended up defending my usage of WordPress from a feature perspective. If I had unlimited time and a fresh slate, even if I stay on WordPress as the CMS, I think I would likely head down a road of at least doing some pre-rendering if not totally de-coupling and building my own front-end and just using the data via APIs. But perhaps the most compelling answers to why come down to speed, security, and resiliency, all of which come along for the ride immediately when you go JAMstack. It provides a hell of a foundation to build on.

The post Random Notes from a JAMstack Roundtable appeared first on CSS-Tricks.

CSS-Tricks

, , , ,
[Top]

Branching Out from the Great Divide

I like the term Front-End Developer. It’s encapsulates the nature of your job if your concerns are:

  • Building UIs for web browsers
  • The spectrum of devices and platforms those web browsers run on
  • The people who use those web browsers and related assistive technology

The breadth of knowledge for all-things front-end development has gotten super deep. I’ve found that front-end developers that have stretched themselves to the point they are thinking of themselves as full-stack developers more and more. I think that’s kinda cool and empowering, but it doesn’t mean that everyone needs to go that wide.

Brad Frost referred to sides of the spectrum as “back of the front” and “front of the front.” I once drew the line, in The Great Divide, as heavy JavaScript vs. not. These distinctions aren’t to divide people, but to acknowledge the spectrum and that there are people all over it.

In a new article called “Frontend Design, React, and a Bridge over the Great Divide,” Brad makes the point that the role of “Front-End Designer” exists on the spectrum right smack in the middle between design and development, where “development” refers to the back-end or deeper JavaScript stuff.

The jobs?

  • Crafting semantic HTML markup
  • Creating CSS code
  • Authoring JavaScript that primarily manipulates objects in the DOM
  • Testing across browsers and devices
  • Optimizing the performance of front-end code
  • Working with designers
  • Working with back-end and application developers

That sounds like the “traditional” explanation of a front-end developer to me — if there is such a thing — but it makes sense to rename that role since front-end development is the term that got so wide.

Brad adds these responsibilties to the list:

  • Create a library of presentational UI components
  • Author and document a robust, intuitive component API for each presentational component
  • Determine how flexible or rigid the component library should be
  • Maintain the presentational components as a product

That’s where I think this metaphor comes in:

A tree of nodes branching out, but sharing a common trunk.

Me, Brad and a slew of you out there are front-end developers. We work in browsers and we care about the users and where and how they interact with those browsers. We do the things on Brad’s first list like craft HTML and CSS, work with designs and do testing. We share that common trunk of skills on the tree above.

But Brad is more of a systems designer than I am. His dot lands somewhere differently on that tree. I don’t know if I’m particularly skilled at anything, but my dot definitely falls elsewhere on that tree. Perhaps on an entirely different branch, as I quite like working with JavaScript tooling and logic and APIs and such. The bulk of Brad’s article is about React and finding a place in the realm of front-end development where the job isn’t ignoring React, but working with it in such a way that doesn’t mean every other aspect of development doesn’t have to come along for the ride.

The post Branching Out from the Great Divide appeared first on CSS-Tricks.

CSS-Tricks

, , ,
[Top]

Lessons Learned from a Year of Testing the Web Platform

Mike Pennisi:

The web-platform-tests project is a massive suite of tests (over one million in total) which verify that software (mostly web browsers) correctly implement web technologies. It’s as important as it is ambitious: the health of the web depends on a plurality of interoperable implementations.

Although Bocoup has been contributing to the web-platform-tests, or “WPT,” for many years, it wasn’t until late in 2017 that we began collecting test results from web browsers and publishing them to wpt.fyi

Talk about doing God’s work.

The rest of the article is about the incredible pain of scaling a test suite that big. Ultimately Azure Pipelines was helpful.

Direct Link to ArticlePermalink

The post Lessons Learned from a Year of Testing the Web Platform appeared first on CSS-Tricks.

CSS-Tricks

, , , , ,
[Top]

Three Predictions From the State of CSS 2019 Survey

Running a developer survey like the State of CSS is a multi-stage process. First, you need to collect the data. Then, you process it into a usable shape. Finally, you come up with nifty ways to visualize it and release it to the world.

But then, once the dust settles and the traffic dies down comes my favorite part: actually thinking about the data. By taking a deeper look at our data, as well as observing how the community discussed our findings, three unexpected trends ended up coming into focus.

But first, some background for those not already familiar with the project.

I first started the State of JavaScript survey three years ago in 2016 as a way to answer my own uncertainties about the future of web development. At the time, JavaScript fatigue was running wild and I thought a comprehensive developer survey could prove itself the antidote.

The original State of JavaScript 2016 edition

Turns out I hit a nerve: that first survey turned out to be very popular, and our audience has grown each year since, along with the scope of the survey. (I was also joined by Raphael Benitte, creator of the Nivo.js dataviz library, to help me with data processing and visualization.) This year marks the first time we’re pivoting out into a new dimension, namely the not-so-simple world of CSS.

Taking on CSS

Prediction 1: CSS still has a lot of unexplored territory

One of the things we wanted to quantify with the survey was how much of CSS was still left “unexplored.” In other words, what CSS features are developers either unfamiliar with, or else hadn’t yet used. For that reason we decided early-on to focus our Features section on new CSS properties, like shapes, masking, or scroll-snap rather than “boring” floats or tables.

The resulting data paints an interesting picture: it turns out that when you look at it this way, CSS morphs from a familiar landscape to a wild, unexplored jungle.

A look at comparing Flexbox vs. CSS Grid provides a good illustration of this trend. While nearly everybody who’s heard of Flexbox has also used it, only 55% of developers who are aware of CSS Grid have actually tried it. That’s a big gap, especially for a technology as important as CSS Grid!

Layout Features

Or take CSS Shapes: 68% of developers are aware of them, only 31% of that group has actually used the feature.

CSS Shapes

This all points at a big gap between what we collectively want to learn and what we actually know. It’s that potential for growth that is exactly what makes CSS so exciting in 2019.

Prediction 2: Functional CSS will keep rising

If you’re old enough to remember the CSS Zen Garden — or to have actually learned CSS through it (in which case I know how you feel, my back hurts when I get up in the morning as well) — then this next trend might seem weird, or even downright wrong.

CSS Zen Garden: one page, many themes.

Functional CSS rejects the platonic ideal of pure, untainted markup free from any styling concerns and embraces “functional” (aka “atomic” or “utility”) classes. Think <div class="text-red text-medium border-1">...</div>.

Adopting this approach means you can’t magically update your stylesheet and change your entire design without modifying a single line of markup. But be honest, how often does this happen anyway? Compared to the often theoretical elegance of the Zen Garden philosophy, libraries like Tailwind and Tachyons provide tangible, real-world benefits, which explains why they’re so highly regarded. In fact, those take the #1 and #4 spots, respectively, in terms of satisfaction ratio in the CSS Framework category.

Awareness, interest, and satisfaction ratio rankings for CSS frameworks.

Tailwind especially seems to be picking up speed, at least judging by the Twitter engagement from its community in response to the survey results. Having just hit version 1.0, it’s definitely a project to keep an eye on!

Prediction 3: The battle for CSS has just begun

Looking at our data, I can’t help but wonder if “JavaScript fatigue” will soon be replaced by “CSS fatigue.”

When evaluating technologies, it’s important to look not just at raw usage numbers, but also at user satisfaction. After all, you don’t want to jump on the latest bandwagon just to find out its current occupants can’t wait to hop off it.

This scatterplot chart that’s divided into quadrants is perfect for this. It plots usage against satisfaction, making it easy to isolate popular, high-satisfaction tools into their own quadrant.

Usage vs. Satisfaction

What’s apparent in this chart is that the most densely populated area is the “Assess” quadrant. In other words, the low-usage, high-satisfaction technologies that are still battling it out for supremacy. This is exactly the state that the JavaScript ecosystem finds itself in as well. Many contenders, but few decisive winners as of today.

This is not necessarily a bad thing: yes, it does make the average developer’s life harder when it comes to picking the right tool, but hey, this is why we do what we do! Additionally, competition can only be good for the ecosystem as a whole. Once the dust settles, we’ll hopefully end up with the best possible options having survived!

CSS in 2019

Overall, the State of CSS survey shows that this is not your grandpa’s CSS anymore. For years, we developers have loved to complain about the inadequacies of CSS and its lack of powerful features. But in 2019, CSS is challenging us to put our money where our mouthes are: here’s all the features you’ve always wanted. Now what are you going to do about it?

I, for one, am very excited to dive even deeper into this new world of styling. And, of course, to tune back in 2020 to see what new trends we find then!

The post Three Predictions From the State of CSS 2019 Survey appeared first on CSS-Tricks.

CSS-Tricks

, , , , ,
[Top]

Snag Resources from An Event Apart Boston 2019 and Save on Washington D.C. Registration

(This is a sponsored post.)

Hey, so we talked a little bit about An Event Apart Boston 2019 leading up to the event and now there are a ton of resources available from it. I stopped counting the number of links after 50 because there’s way more than that. Seriously, there’s stuff in there on subgrid, working with CSS Regions, design systems, using prefers-reduced-motion… and much, much more, so check it out.

And, while you’re at it, you should consider attending the next installment of An Event Apart. It takes place in Washington D.C. and seating — as you might expect — is limited. Like Boston, you can expect to get a treasure trove of useful information, educational content, and valuable training on topics that will help you sharpen your front-end chops and grow your career. Plus, the best part is getting to meet the rest of the great folks at the event — that’s where your network grows and real conversations take place.

Register Today

Can’t make it to Washington D.C.? No worries, because An Event Apart is also slated to take place in Chicago (), Denver () and San Francisco (). Now’s the time to start planning your trip and begging your boss for a well-deserved self-investment in leveling up.

And if you’re wondering whether we have a discount code for you… of course we do! Enter the AEACP at checkout to knock $ 100 off the price. 🤑

Direct Link to ArticlePermalink

The post Snag Resources from An Event Apart Boston 2019 and Save on Washington D.C. Registration appeared first on CSS-Tricks.

CSS-Tricks

, , , , , , , , , ,
[Top]

Making the Move from jQuery to Vue

As someone who has used jQuery for many. years and has recently become a Vue convert, I thought it would be an interesting topic to discuss the migration process of working with one to the other.

Before I begin though, I want to ensure one thing is crystal clear. I am not, in any way whatsoever, telling anyone to stop using jQuery. That’s been pretty fashionable lately, and heck, I wrote up something similar myself a few year ago (“How I’m (Not) Using jQuery”). If you get things done with jQuery and your end users are successfully using your site, then more power to you. Keep using what works for you.

This guide is more for people who may be coming from years of jQuery experience and want to see how things can be done with Vue. With that in mind, I’m going to focus on what I consider “core” jQuery use cases. I won’t cover every single possible feature but instead take a “I often did [X] with jQuery” approach that may be more relatable to people considering learning Vue. (As an aside, also note that how I write my examples are simply one way of performing a task. Both jQuery and Vue give provide multiple ways to accomplish the same goal and that’s a great thing!)

With that in mind, let’s consider some high level things we might turn to jQuery for:

  • Finding something in the DOM (with the idea of doing something with it later)
  • Changing something in the DOM (e.g. the text of a paragraph or the class of a button)
  • Reading and setting form values
  • Form validation (which is really just a combination of the items above)
  • Ajax calls and handling the results
  • Event handling (e.g. on button click, do something)
  • Measuring or changing the styles of an element

There’s more to jQuery, of course, but these uses (at least in my opinion), cover the most common use cases. Also note there’s a lot of cross pollination in the list above. So, should we start with a simple one-to-one comparison of each? Nope, not so fast. Let’s begin by covering the major difference in Vue applications.

Defining where Vue “works”

When we drop jQuery onto a page, we are basically adding a Swiss Army knife to JavaScript code to handle common web development tasks. We can do any of the uses case we’re going to cover in whatever order we see fit. For example, a client may ask for form validation today, then in a month or so, ask to do an Ajax-based search form in the header of the site.

Vue has one significant difference in that respect. When starting a with Vue project, we start by defining an “area” in the DOM we want it to focus on. So, let’s consider a simple prototype web page:

<body>    <header>     Fancy header stuff here   </header>    <div id="sidebar">     Some sidebar doohicky here   </div>    <main>     <p>       Main site content here, super important stuff...     </p>     <div id="loginForm">       A login form of course     </div>   </main>  </body>

In a typical jQuery application, we may write code to work with the header, sidebar, and login form or something. No big whoop:

$  (document).ready(function() {    $  ('header') // something...    $  ('#sidebar') // something...    $  ('#loginForm') // something...   });

In a Vue application, we first specify what are we’re working with. Imagine our client first asked to add validation to the loginForm element. Our Vue code would specify that:

new Vue({   el: '#loginForm',   // Code here... });

This means that we’d typically end up adding a second Vue application if the client later decides to have us add something to the sidebar:

new Vue({   el:'#loginForm',   // Code here... });  new Vue({   el:'#sideBar',   // Code here... });

Is that a bad thing? Absolutely not. Right away, we get the benefit of encapsulation. If we accidentally use a variable with a generic name (we’ve all done that), we don’t have to worry about conflicts with other parts of your code. Later on when the client adds yet another request, having our unique, logical sets of Vue code separated out like this gives us some great peace of mind that things won’t step on each other.

So, yes, a good thing. But it absolutely caused me to stop a bit when I first began using Vue. Now, onto our use cases.

Finding Stuff in the DOM

Another aspect you’ll find interesting, or scary, is how to “find stuff in the DOM.” That’s a bit vague, but let’s consider a firm example. We have a button, and when it’s clicked, we something to happen. Here’s an abbreviated example of how this could look:

<button id="myButton">Click Me!</button> <!-- More stuff... --> <script> $  (document).ready(function() {    $  ('#myButton').click(function() {     alert(1);   });  }); </script>

Now let’s compare that to how it can be done with Vue:

<div id="app">   <button v-on:click="doSomething">Click Me!</button> </div>  <script> const app = new Vue({   el:'#app',   methods: {     doSomething: function() {       alert(1);     }   } }); </script>

The Vue application is a bit more verbose, but note how the markup has a direct connection between the action (“click”) and the function that will be called. Vue’s code doesn’t have a tie back to the DOM (outside of the el portion where we define where it needs to work). This was easily one of the things that sold me on Vue the most — it feels easier to tell what is going on. Also, I didn’t need to worry so much about the ID value and selectors. If I change the class or ID of the button, I don’t need to go back into my code and worry about updating selectors.

Let’s consider another example: finding and changing text in the DOM. Imagine that button, on click, now changes the text of another part of the DOM.

<button id="myButton">Click Me!</button> <span id="result"></span>  <!-- More stuff... -->  <script> $  (document).ready(function() {    $  ('#myButton').click(function() {     $  ('#result').text('You clicked me, thanks!');   });  }); </script>

I’ve added a new span and now, when the button is clicked, we use another selector to find it and use a jQuery utility method to change the text inside it. Now consider the Vue version:

<div id="app">   <button v-on:click="doSomething">Click Me!</button>   <!-- On click, change text in this span -->   <span>{{resultText}}</span> </div>  <script> const app = new Vue({   el: '#app',   data: {     resultText: ''   },   methods: {     doSomething: function() {       this.resultText = 'You clicked me, thanks!';     }   } }); </script>

In this example, we’re using Vue’s template language (the highlighted line) to specify that we want to render a variable inside the span, which is resultText in this case. Now, when the button is clicked, we change that value and the span’s inner text will change automatically.

As an aside, Vue supports a shorthand for the v-on attribute, so the button in the example could have been written with @click="doSomething" instead.

Reading and writing form variables

Working with forms is probably one of the most common — and useful — things that we can do with JavaScript. Even before JavaScript, most of my early “web development” was writing Perl script to handle form submissions. As the primary way of accepting user input, forms have always been critical to the web and that’s probably going to stay the same for quite some time. Let’s consider a simple jQuery example of reading a few form fields and setting another:

<form>   <input type="number" id="first"> +    <input type="number" id="second"> =   <input type="number" id="sum">    <button id="sumButton">Sum</button> </form>  <script> $  (document).ready(function() {   let $  first = $  ('#first');   let $  second = $  ('#second');   let $  sum = $  ('#sum');   let $  button = $  ('#sumButton');      $  button.on('click', function(e) {     e.preventDefault();     let total = parseInt($  first.val(),10) + parseInt($  second.val(),10);     $  sum.val(total);   }); }); </script>

This code demonstrates how jQuery can both read and write via the val() method. We end up getting four items from the DOM (all three form fields and the button) and use simple math to generate a result. Now consider the Vue version:

<form id="myForm">   <input type="number" v-model.number="first"> +    <input type="number" v-model.number="second"> =   <input type="number" v-model="sum">    <button @click.prevent="doSum">Sum</button> </form>  <script> new Vue({   el: '#myForm',   data: {     first: 0,     second: 0,     sum: 0   },   methods: {     doSum: function() {       this.sum = this.first + this.second;     }   } }) </script>

This introduces some interesting Vue shortcuts. First, v-model is how Vue creates two way data binding between values in the DOM and in JavaScript. The data block variables will automatically sync up with the form fields. Change the data, and the form updates. Change the form, and the data updates. The .number is a flag to Vue to treat the inherit string values of form fields as numbers. If we leave this off and do addition as we are, we’ll see string additions and not arithmetic. I’ve been working with JavaScript for nearly a century and still screw this up.

Another neat “trick” is @click.prevent. First, @click defines a click handler for the button, then the .prevent portion blocks the browser’s default behavior of submitting the form (the equivalent of event.preventDefault()).

The final bit is the addition of the doSum method that’s bound to that button. Note that it simply works with the data variables (which Vue makes available in the this scope).

While this is mostly my personal feeling here, I really love the lack of query selectors in the script when writing in Vue and how the HTML is much more clear about what it’s doing.

Finally, we could even get rid of the button completely:

<form id="myForm">   <input type="number" v-model.number="first"> +    <input type="number" v-model.number="second"> =   <input type="number" v-model="sum">  </form>  <script> new Vue({   el: '#myForm',   data: {     first: 0,     second: 0   },   computed: {     sum: function() {       return this.first + this.second;     }   } }) </script>

One of the cooler features of Vue is computed properties. They are virtual values that recognize when their derived values are updated. In the code above, as soon as any of the two form fields change, the sum will update. This works outside of form fields too. We could render the sum like so:

The total is {{sum}}.

Working with Ajax

It’s commendable how easy jQuery has made it to use Ajax. In fact, I can say I’ve done Ajax “the vanilla” way probably a grand total of one time. (If you’re curious, you can take a look at the spec for XMLHttpRequest and probably be happy you avoided it yourself.) jQuery’s simple $ .get(...) method worked in a large number of cases and when it’s needed for something more complex, $ .ajax() made it easy as well. Another thing jQuery did well is the way it handles JSONP requests. While mostly unnecessary now with CORS, JSONP was a way to handle making requests to APIs on different domains.

So, what does Vue do for you to make Ajax easier? Nothing!

OK, that sounds scary but it really isn’t. There are many options out there for working with HTTP requests, and Vue.js took a more agnostic route of letting us, the developers, decide how we want to handle it. So yes, that does mean a bit more work, but we’ve got some great options.

The first one to consider is Axios, this is a Promise-based library that is very popular among the Vue community. Here’s a simple example of it in action (taken from their README file):

axios.get('/user?ID=12345')   .then(function (response) {     // handle success     console.log(response);   })   .catch(function (error) {     // handle error     console.log(error);   })   .then(function () {     // always executed   });

Axios supports POST requests, of course, and lets us specify headers among many other options.

While Axios is very popular among Vue developers, it isn’t something that really clicked with me. (At least not yet.) Instead, I’ve been much more a fan of Fetch. Fetch is not an external library but is a web standard way of performing HTTP requests. Fetch has very good support at roughly 90% of browsers, though that means it isn’t completely safe to use, but we can always use a polyfill we need to.

While it’s totally out of the scope of what we’re discussing here, Kingsley Silas has written an excellent guide on using both Axios and Fetch with React.

Like Axios, Fetch is Promise-based and has a friendly API:

fetch('http://example.com/movies.json')   .then(function(response) {     return response.json();   })   .then(function(myJson) {     console.log(JSON.stringify(myJson));   });

Both Axios and Fetch cover all types of HTTP requests, so either will fit an any number of needs. Let’s look at a simple comparison. Here’s a simple jQuery demo that makes use of the Star Wars API.

<h1>Star Wars Films</h1> <ul id="films"> </ul>  <script> $  (document).ready(function() {   $  .get('https://swapi.co/api/films', function(res) {     let list = '';     res.results.forEach(function(r) {       list += `<li>$  {r.title}</li>`;     });     $  ('#films').html(list);   }); }); </script>

In the sample above, I use $ .get to hit the API and return a list of films. Then I generate a list of titles as li tag elements with that data and insert it all into a ul block.

Now, let’s consider an example of this using Vue:

<div id="app">   <h1>Star Wars Films</h1>   <ul>     <li v-for="film in films">{{film.title}}</li>   </ul>   </div>  <script> const app = new Vue({   el: '#app',   data: {     films: []   },    created() {      fetch('https://swapi.co/api/films')     .then(res => res.json())     .then(res => {       this.films = res.results;       });   } }) </script>

Probably the best part of this is the use of the v-for template. Notice how Vue isn’t concerned with the layout (well, at least the JavaScript). The data is fetched from the API. It’s assigned a variable. The layout handles displaying it. I’ve always hated having HTML in my JavaScript and, while solutions exist for that with jQuery, having it baked into Vue makes it a natural fit.

A full (if somewhat trivial) example

To bring it home a bit, let’s consider a more real world example. Our client has asked us to build a fancy Ajax-enabled front-end search interface to a product API. The feature list includes:

  • Support filtering by name and product category
  • Form validation such that we must supply a search term or a category
  • While the API is being hit, show a message to the user and disable the submit button
  • When done, handle reporting that no products were shown or list the matches

Let’s begin with the jQuery version. First, the HTML:

<form>   <p>     <label for="search">Search</label>     <input type="search" id="search">   </p>   <p>     <label for="category">Category</label>     <select id="category">       <option></option>       <option>Food</option>       <option>Games</option>     </select>   </p>    <button id="searchBtn">Search</button> </form>  <div id="status"></div> <div id="results"></div>

There’s a form with our two filters and two divs. One’s used as a temporary status when searching or reporting errors and one is used to render results. Now, check out the code.

const productAPI = 'https://wt-c2bde7d7dfc8623f121b0eb5a7102930-0.sandbox.auth0-extend.com/productSearch';  $  (document).ready(() => {   let $  search = $  ('#search');   let $  category = $  ('#category');   let $  searchBtn = $  ('#searchBtn');   let $  status = $  ('#status');   let $  results = $  ('#results');      $  searchBtn.on('click', e => {     e.preventDefault();          // First clear previous stuff     $  status.html('');     $  results.html('');      // OK, now validate form     let term = $  search.val();     let category = $  category.val();     if(term === '' && category === '') {       $  status.html('You must enter a term or select a category.');       return false;     }      $  searchBtn.attr('disabled','disabled');     $  status.html('Searching - please stand by...');          $  .post(productAPI, { name:term, category:category }, body => {       $  searchBtn.removeAttr('disabled');       $  status.html('');        if(body.results.length === 0) {         $  results.html('<p>Sorry, no results!</p>');         return;       }              let result = '<ul>';       body.results.forEach(r => {         result += `<li>$  {r.name}</li>`       });       result += '</ul>';       $  results.html(result);     });        }); });

The code begins by creating a set of variables for each of the DOM items we want to work with — the form fields, button, and divs. The core of the logic is within the click handler for the button. We do validation, and if everything is OK, do a POST request against the API. When it returns, we either render the results or show a message if nothing was matched.

You can work with a complete version of this demo using the CodePen below.

See the Pen
jQuery Full
by Raymond Camden (@cfjedimaster)
on CodePen.

Now let’s consider the Vue version. Again, let’s start with the layout:

<div id="app">   <form>     <p>       <label for="search">Search</label>       <input type="search" v-model="search">     </p>     <p>       <label for="category">Category</label>       <select v-model="category">         <option></option>         <option>Food</option>         <option>Games</option>       </select>     </p>     <button @click.prevent="searchProducts" :disabled="searchBtnDisabled">Search</button>   </form>      <div v-html="status"></div>     <ul v-if="results">       <li v-for="result in results">{{result.name}}</li>     </ul> </div>

From the top, the changes include:

  • Wrapping the layout in a div that can be used to let Vue know where to work.
  • Using v-model for the form fields to make it easy to work with the data.
  • Using @click.prevent to handle doing the main search operation.
  • Using :disabled to bind whether or not the button is disabled to a value in the Vue application (we’ll see that in action in a moment).
  • The status value is a bit different than earlier examples. While jQuery has a specific method to set text in a DOM item and another for HTML, Vue requires using v-html when assigning HTML to a value that’s going to be rendered. If we tried to do {{status}} with HTML, the tags would be escaped.
  • Finally, using v-if to conditionally render a list of results along with v-for to handle the iteration.

Now let’s look at the code.

const productAPI = 'https://wt-c2bde7d7dfc8623f121b0eb5a7102930-0.sandbox.auth0-extend.com/productSearch';  const app = new Vue({   el: '#app',   data: {     search: '',     category: '',     status: '',     results: null,     searchBtnDisabled: false   },   methods: {     searchProducts:function() {       this.results = null;       this.status = '';              if(this.search === '' && this.category === '') {         this.status = 'You must enter a term or select a category.';         return;       }        this.searchBtnDisabled = true;       this.status = 'Searching - please stand by...';              fetch(productAPI, {         method: 'POST',         headers: {           'Content-Type':'application/json'         },         body: JSON.stringify({name:this.search,category:this.category})       }).then(res => res.json())       .then(res => {         this.status = '';         this.searchBtnDisabled = false;         this.results = res.results;         if(this.results.length === 0) this.status = '<p>Sorry, no results!</p>';       });            }   } });

The first block worth calling out is the set of data fields. Some map to form fields and others to results, status messages, and the like. The searchProducts method handles much of the same stuff as the jQuery version but, in general, there’s much less code directly tied to the DOM. For example, even though we know the results are listed in an unordered list, the code itself doesn’t worry about that. It simply assigns the value and the markup handles rendering it. Overall, the JavaScript code is much more concerned about logic in comparison to the jQuery code which “feels” like a much nicer separation of concerns.

As before, I’ve got a CodePen for you to try this out yourself:

See the Pen
Vue Full
by Raymond Camden (@cfjedimaster)
on CodePen.

Death to jQuery! Long Live Vue!

OK, that’s a bit over the top. As I said in the beginning, I absolutely think that you shouldn’t change a thing if like working with jQuery and it’s working for you.

I can say, however, that Vue feels like a great “next step” for people who are used to working with jQuery. Vue supports complex applications and has a great command line tool for scaffolding and building projects. But for simpler tasks, Vue works as a great “modern jQuery” replacement that has become my tool of choice for development!

For another perspective on using Vue in place of jQuery, check out Sarah Drasner’s “Replacing jQuery With Vue.js: No Build Step Necessary” because it includes a handful of other super helpful examples.

The post Making the Move from jQuery to Vue appeared first on CSS-Tricks.

CSS-Tricks

, , ,
[Top]

Moving from Gulp to Parcel

Ben Frain just made some notes about the switch from Gulp to Parcel, a relatively new “web application bundler” which, from a quick look at things, is similar to webpack but without all the hassle of setting things up. One of the things I’ve always disliked about webpack is that you kinda have to teach it what CSS, HTML and JS are before making whatever modifications you want to those files. However, Parcel does a lot of the asset management and configuration stuff for us which is super neat — hence, Parcel claim that it requires “zero configuration.”

If you’d like to learn more about Parcel then there’s a great post by Indrek Lasn that details how to get started and even shows off a little bit about how Parcel is often faster than alternatives like webpack. We also just published a post by Kingsley Silas that explains how to use Parcel with React.

Direct Link to ArticlePermalink

The post Moving from Gulp to Parcel appeared first on CSS-Tricks.

CSS-Tricks

, , ,
[Top]

Creating a Custom Element from Scratch

In the last article, we got our hands dirty with Web Components by creating an HTML template that is in the document but not rendered until we need it.

Next up, we’re going to continue our quest to create a custom element version of the dialog component below which currently only uses HTMLTemplateElement:

See the Pen
Dialog with template with script
by Caleb Williams (@calebdwilliams)
on CodePen.

So let’s push ahead by creating a custom element that consumes our template#dialog-template element in real-time.

Article Series:

  1. An Introduction to Web Components
  2. Crafting Reusable HTML Templates
  3. Creating a Custom Element from Scratch (This post)
  4. Encapsulating Style and Structure with Shadow DOM (Coming soon!)
  5. Advanced Tooling for Web Components (Coming soon!)

Creating a custom element

The bread and butter of Web Components are custom elements. The customElements API gives us a path to define custom HTML tags that can be used in any document that contains the defining class.

Think of it like a React or Angular component (e.g. <MyCard />), but without the React or Angular dependency. Native custom elements look like this: <my-card></my-card>. More importantly, think of it as a standard element that can be used in your React, Angular, Vue, [insert-framework-you’re-interested-in-this-week] applications without much fuss.

Essentially, a custom element consists of two pieces: a tag name and a class that extends the built-in HTMLElement class. The most basic version of our custom element would look like this:

class OneDialog extends HTMLElement {   connectedCallback() {     this.innerHTML = `<h1>Hello, World!</h1>`;   } }  customElements.define('one-dialog', OneDialog);

Note: throughout a custom element, the this value is a reference to the custom element instance.

In the example above, we defined a new standards-compliant HTML element, <one-dialog></one-dialog>. It doesn’t do much… yet. For now, using the <one-dialog> tag in any HTML document will create a new element with an <h1> tag reading “Hello, World!”

We are definitely going to want something more robust, and we’re in luck. In the last article, we looked at creating a template for our dialog and, since we will have access to that template, let’s utilize it in our custom element. We added a script tag in that example to do some dialog magic. let’s remove that for now since we’ll be moving our logic from the HTML template to inside the custom element class.

class OneDialog extends HTMLElement {   connectedCallback() {     const template = document.getElementById('one-dialog');     const node = document.importNode(template.content, true);     this.appendChild(node);   } }

Now, our custom element (<one-dialog>) is defined and the browser is instructed to render the content contained in the HTML template where the custom element is called.

Our next step is to move our logic into our component class.

Custom element lifecycle methods

Like React or Angular, custom elements have lifecycle methods. You’ve already been passively introduced to connectedCallback, which is called when our element gets added to the DOM.

The connectedCallback is separate from the element’s constructor. Whereas the constructor is used to set up the bare bones of the element, the connectedCallback is typically used for adding content to the element, setting up event listeners or otherwise initializing the component.

In fact, the constructor can’t be used to modify or manipulate the element’s attributes by design. If we were to create a new instance of our dialog using document.createElement, the constructor would be called. A consumer of the element would expect a simple node with no attributes or content inserted.

The createElement function has no options for configuring the element that will be returned. It stands to reason, then, that the constructor shouldn’t have the ability to modify the element that it creates. That leaves us with the connectedCallback as the place to modify our element.

With standard built-in elements, the element’s state is typically reflected by what attributes are present on the element and the values of those attributes. For our example, we’re going to look at exactly one attribute: [open]. In order to do this, we’ll need to watch for changes to that attribute and we’ll need attributeChangedCallback to do that. This second lifecycle method is called whenever one of the element constructor’s observedAttributes are updated.

That might sound intimidating, but the syntax is pretty simple:

class OneDialog extends HTMLElement {   static get observedAttributes() {     return ['open'];   }      attributeChangedCallback(attrName, oldValue, newValue) {     if (newValue !== oldValue) {       this[attrName] = this.hasAttribute(attrName);     }   }      connectedCallback() {     const template = document.getElementById('one-dialog');     const node = document.importNode(template.content, true);     this.appendChild(node);   } }

In our case above, we only care if the attribute is set or not, we don’t care about a value (this is similar to the HTML5 required attribute on inputs). When this attribute is updated, we update the element’s open property. A property exists on a JavaScript object whereas an attribute exists on an HTMLElement, this lifecycle method helps us keep the two in sync.

We wrap the updater inside the attributeChangedCallback inside a conditional checking to see if the new value and old value are equal. We do this to prevent an infinite loop inside our program because later we are going to create a property getter and setter that will keep the property and attributes in sync by setting the element’s attribute when the element’s property gets updated. The attributeChangedCallback does the inverse: updates the property when the attribute changes.

Now, an author can consume our component and the presence of the open attribute will dictate whether or not the dialog will be open by default. To make that a bit more dynamic, we can add custom getters and setters to our element’s open property:

class OneDialog extends HTMLElement {   static get boundAttributes() {     return ['open'];   }      attributeChangedCallback(attrName, oldValue, newValue) {     this[attrName] = this.hasAttribute(attrName);   }      connectedCallback() {     const template = document.getElementById('one-dialog');     const node = document.importNode(template.content, true);     this.appendChild(node);   }      get open() {     return this.hasAttribute('open');   }      set open(isOpen) {     if (isOpen) {       this.setAttribute('open', true);     } else {       this.removeAttribute('open');     }   } }

Our getter and setter will keep the open attribute (on the HTML element) and property (on the DOM object) values in sync. Adding the open attribute will set element.open to true and setting element.open to true will add the open attribute. We do this to make sure that our element’s state is reflected by its properties. This isn’t technically required, but is considered a best practice for authoring custom elements.

This does inevitably lead to a bit of boilerplate, but creating an abstract class that keeps the these in sync is a fairly trivial task by looping over the observed attribute list and using Object.defineProperty.

Now that we know whether or not our dialog is open, let’s add some logic to actually do the showing and hiding:

class OneDialog extends HTMLElement {     /** Omitted */   constructor() {     super();     this.close = this.close.bind(this);   }      set open(isOpen) {     this.querySelector('.wrapper').classList.toggle('open', isOpen);     this.querySelector('.wrapper').setAttribute('aria-hidden', !isOpen);     if (isOpen) {       this._wasFocused = document.activeElement;       this.setAttribute('open', '');       document.addEventListener('keydown', this._watchEscape);       this.focus();       this.querySelector('button').focus();     } else {       this._wasFocused && this._wasFocused.focus && this._wasFocused.focus();       this.removeAttribute('open');       document.removeEventListener('keydown', this._watchEscape);       this.close();     }   }      close() {     if (this.open !== false) {       this.open = false;     }     const closeEvent = new CustomEvent('dialog-closed');     this.dispatchEvent(closeEvent);   }      _watchEscape(event) {     if (event.key === 'Escape') {         this.close();        }   } }

There’s a lot going on here, but let’s walk through it. The first thing we do is grab our wrapper and toggle the .open class based on isOpen. To keep our element accessible, we need to toggle the aria-hidden attribute as well.

If the dialog is open, then we want to save a reference to the previously-focused element. This is to account for accessibility standards. We also add a keydown listener to the document called watchEscape that we have bound to the element’s this in the constructor in a pattern similar to how React handles method calls in class components.

We do this not only to ensure the proper binding for this.close, but also because Function.prototype.bind returns an instance of the function with the bound call site. By saving a reference to the newly-bound method in the constructor, we’re able to then remove the event when the dialog is disconnected (more on that in a moment). We finish up by focusing on our element and setting setting the focus on the proper element in our shadow root.

We also create a nice little utility method for closing our dialog that dispatches a custom event alerting some listener that the dialog has been closed.

If the element is closed (i.e. !open), we check to make sure the this._wasFocused property is defined and has a focus method and call that to return the user’s focus back to the regular DOM. Then we remove our event listener to avoid any memory leaks.

Speaking of cleaning up after ourselves, that takes us to yet another lifecycle method: disconnectedCallback. The disconnectedCallback is the inverse of the connectedCallback in that the method is called once the element is removed from the DOM and allows us to clean up any event listeners or MutationObservers attached to our element.

It just so happens we have a few more event listeners to wire up:

class OneDialog extends HTMLElement {   /** Omitted */      connectedCallback() {         this.querySelector('button').addEventListener('click', this.close);     this.querySelector('.overlay').addEventListener('click', this.close);   }      disconnectedCallback() {     this.querySelector('button').removeEventListener('click', this.close);     this.querySelector('.overlay').removeEventListener('click', this.close);   }   }

Now we have a well-functioning, mostly accessible dialog element. There are a few bits of polish we can do, like capturing focus on the element, but that’s outside the scope of what we’re trying to learn here.

There is one more lifecycle method that doesn’t apply to our element, the adoptedCallback, which fires when the element is adopted into another part of the DOM.

In the following example, you will now see that our template element is being consumed by a standard <one-dialog> element.

See the Pen
Dialog example using template
by Caleb Williams (@calebdwilliams)
on CodePen.

Another thing: non-presentational components

The <one-template> we have created so far is a typical custom element in that it includes markup and behavior that gets inserted into the document when the element is included. However, not all elements need to render visually. In the React ecosystem, components are often used to manage application state or some other major functionality, like <Provider /> in react-redux.

Let’s imagine for a moment that our component is part of a series of dialogs in a workflow. As one dialog is closed, the next one should open. We could make a wrapper component that listens for our dialog-closed event and progresses through the workflow.

class DialogWorkflow extends HTMLElement {   connectedCallback() {     this._onDialogClosed = this._onDialogClosed.bind(this);     this.addEventListener('dialog-closed', this._onDialogClosed);   }    get dialogs() {     return Array.from(this.querySelectorAll('one-dialog'));   }    _onDialogClosed(event) {     const dialogClosed = event.target;     const nextIndex = this.dialogs.indexOf(dialogClosed);     if (nextIndex !== -1) {       this.dialogs[nextIndex].open = true;     }   } }

This element doesn’t have any presentational logic, but serves as a controller for application state. With a little effort, we could recreate a Redux-like state management system using nothing but a custom element that could manage an entire application’s state in the same one that React’s Redux wrapper does.

That’s a deeper look at custom elements

Now we have a pretty good understanding of custom elements and our dialog is starting to come together. But it still has some problems.

Notice that we’ve had to add some CSS to restyle the dialog button because our element’s styles are interfering with the rest of the page. While we could utilize naming strategies (like BEM) to ensure our styles won’t create conflicts with other components, there is a more friendly way of isolating styles. Spoiler! It’s shadow DOM and that’s what we’re going to look at in the next part of this series on Web Components.

Another thing we need to do is define a new template for every component or find some way to switch templates for our dialog. As it stands, there can only be one dialog type per page because the template that it uses must always be present. So either we need some way to inject dynamic content or a way to swap templates.

In the next article, we will look at ways to increase the usability of the <one-dialog> element we just created by incorporating style and content encapsulation using the shadow DOM.

Article Series:

  1. An Introduction to Web Components
  2. Crafting Reusable HTML Templates
  3. Creating a Custom Element from Scratch (This post)
  4. Encapsulating Style and Structure with Shadow DOM (Coming soon!)
  5. Advanced Tooling for Web Components (Coming soon!)

The post Creating a Custom Element from Scratch appeared first on CSS-Tricks.

CSS-Tricks

, , , ,
[Top]