Tag: Know

Some Things You Oughta Know When Working with Viewport Units

David Chanin has a quickie article summarizing a problem with setting an element’s height to 100vh in mobile browsers and then also positioning something on the bottom of that.

Summarized in this graphic:

The trouble is that Chrome isn’t taking the address bar (browser chrome) into account when it’s revealed which cuts off the element short, forcing the bottom of the element past the bottom of the actual viewport.

<div class="full-page-element">   <button>Button</button> </div>
.full-page-element {   height: 100vh;   position: relative; }  .full-page-element button {   position: absolute;   bottom: 10px;   left: 10px; }

You’d expect that button in the graphic to be visible (assuming this element is at the top of the page and you haven’t scrolled) since it’s along the bottom edge of a 100vh element. But it’s actually hidden behind the browser chrome in mobile browsers, including iOS Safari or Android Chrome.

I use this a lot:

body {   height: 100vh; /* Nice to not have to think about the HTML element parent   margin: 0; }

It’s just a quick way to make sure the body is full height without involving any other elements. I’m usually doing that on pretty low-stakes demo type stuff, but I’m told even that is a little problematic because you might experience jumpiness as browser chrome appears and disappears, or things may not be quite as centered as you’d expect.

You’d think you could do body { height: 100% }, but there’s a gotcha there as well. The body is a child of <html> which is only as tall as the content it contains, just like any other element.

If you need the body to be full height, you have to deal with the HTML element as well:

html, body {    height: 100%; }

…which isn’t that big of a deal and has reliable cross-browser consistency.

It’s the positioning things along the bottom edge that is tricky. It is problematic because of position: absolute; within the “full height” (often taller-than-visible) container.

If you are trying to place something like a fixed navigation bar at the bottom of the screen, you’d probably do that with position: fixed; bottom: 0; and that seems to work fine. The browser chrome pushes it up and down as you’d expect (video).

Horizontal viewport units are just as weird and problematic due to another bit of browser UI: scrollbars. If a browser window has a visible scrollbar, that scrollbar will usually eat into the visual space although a value of 100vw is calculated as if the scrollbar wasn’t there. In other words, 100vw will cause horizontal scrolling in a way you probably wouldn’t expect.

See the Pen
CSS Vars for viewport width minus scrollbar
by Shaw (@shshaw)
on CodePen.

Our last CSS wishlist roundup mentioned better viewport unit handling a number of times, so developers are clearly pretty interested in having better solutions for these things. I’m not sure what that would mean for web compatibility though, because changing the way they work might break all the workarounds we’ve used that are surely still out in the wild.

The post Some Things You Oughta Know When Working with Viewport Units appeared first on CSS-Tricks.

CSS-Tricks

, , , , , ,

Which CSS IS AWESOME makes the most sense if you don’t know CSS well?

Peter-Paul posted this question:

Note the interesting caveat: only vote in the poll if you don’t know CSS well.

The winning answer was D! You gotta wonder if the result would have been different if the request for non-CSS experts wasn’t there.

I like to think I know CSS OK, so I didn’t vote. My brain goes like this:

  1. I think he’s asking “by default,” so the answer may assume there’s no other CSS doing anything to that text.
  2. I wish I knew why the box was that particular width, but I guess I’ll just assume it’s a set width.
  3. It’s not B because ellipsis stuff requires extra stuff, and doesn’t work on multiple lines like that — unless we’re talking line clamping, which is even weirder.
  4. It’s not C because that requires hiding overflow which is never really a default — that is, except off the top and left of the browser window, I guess. Or in an iframe.
  5. It’s not D because words just don’t break like that unless you do pretty specific stuff.
  6. A actually makes decent sense. It’s weird to look at, but I’ve been dealing with stuff busting out of containers my whole career. C’est la vie.

Remember, we’ve done a deep dive into CSS IS AWESOME before and how it interestingly captures the weirdness of CSS.

The post Which CSS IS AWESOME makes the most sense if you don’t know CSS well? appeared first on CSS-Tricks.

CSS-Tricks

, , , , , ,
[Top]

Which CSS IS AWESOME makes the most sense if you don’t know CSS well?

Peter-Paul posted this question:

Note the interesting caveat: only vote in the poll if you don’t know CSS well.

The winning answer was D! You gotta wonder if the result would have been different if the request for non-CSS experts wasn’t there.

I like to think I know CSS OK, so I didn’t vote. My brain goes like this:

  1. I think he’s asking “by default,” so the answer may assume there’s no other CSS doing anything to that text.
  2. I wish I knew why the box was that particular width, but I guess I’ll just assume it’s a set width.
  3. It’s not B because ellipsis stuff requires extra stuff, and doesn’t work on multiple lines like that — unless we’re talking line clamping, which is even weirder.
  4. It’s not C because that requires hiding overflow which is never really a default — that is, except off the top and left of the browser window, I guess. Or in an iframe.
  5. It’s not D because words just don’t break like that unless you do pretty specific stuff.
  6. A actually makes decent sense. It’s weird to look at, but I’ve been dealing with stuff busting out of containers my whole career. C’est la vie.

Remember, we’ve done a deep dive into CSS IS AWESOME before and how it interestingly captures the weirdness of CSS.

The post Which CSS IS AWESOME makes the most sense if you don’t know CSS well? appeared first on CSS-Tricks.

CSS-Tricks

, , , , , ,
[Top]

Getting to Know the useReducer React Hook

useReducer is one of a handful of React hooks that shipped in React 16.7.0. It accepts a reducer function with the application initial state, returns the current application state, then dispatches a function.

Here is an example of how it is used;

const [state, dispatch] = useReducer(reducer, initialState);

What’s the good for? Well, think about any situation where having the first loaded state of the application might be nice. Let’s say the starting point on an interactive map. Maybe it’s an app that lets the user build a custom car with custom options from a default model. Here’s a pretty neat demo of a calculator app that puts useRedcuer to use in order to reset the calculator to a default state of zero when clearing it out.

See the Pen
Basic React Hook Calculator
by Gianpierangelo De Palma (@dpgian)
on CodePen.

We’re going to dig into a couple more examples in this post, but let’s first look at the hook itself to get a better idea of what it is and what exactly it does when it’s used.

The almighty reducer

It’s tough to talk about useState without also mentioning JavaScript’s reduce method. We linked it up at the very top, but Sarah’s post is an excellent overview of reducers and helps set the state for where we’re going here.

The first and most important thing to understand about a reducer is that it will always only return one value. The job of a reducer is to reduce. That one value can be a number, a string, an array or an object, but it will always only be one. Reducers are really great for a lot of things, but they’re especially useful for applying a bit of logic to a group of values and ending up with another single result.

So, if we have an array of numbers, reduce will distill it down to a single number that adds up for as many times as there are values. Say we have this simple array:

const numbers = [1, 2, 3]

…and we have a function that logs each time our reducer makes a calculation into the console. This will help us see how reduce distills the array into a single number.

const reducer = function (tally, number) {  	console.log(`Tally: $  {tally}, Next number: $  {number}, New Total: $  {tally + number}`) 	return tally + number }

Now let’s run a reducer on it. As we saw earlier, reduce takes dispatches a function that runs against a default state. Let’s plug our reducer function and an initial value of zero in there.

const total = numbers.reduce(reducer, 0)

Here’s what gets logged to the console:

"Tally: 0, Next number: 1, New Total: 1" "Tally: 1, Next number: 2, New Total: 3" "Tally: 3, Next number: 3, New Total: 6"

See how reduce takes an initial value and builds on it as each number in the array is added to it until we get a final value? In this case, that final value is 6.

I also really like this (modified) example from Dave Ceddia that shows how reduce can be used on an array of letters to spell a word:

var letters = ['r', 'e', 'd', 'u', 'c', 'e'];  // `reduce` takes 2 arguments: //   - a function to do the reducing (you might say, a "reducer") //   - an initial value for accumulatedResult var word = letters.reduce( 	function(accumulatedResult, arrayItem) { 		return accumulatedResult + arrayItem; 	}, ''); // <-- notice this empty string argument: it's the initial value  console.log(word) // => "reduce"

useReducer works with states and actions

OK, that was a lot of refresher to get what we’re really talking about: userReducer. It’s important to get all this, though, because you may have noticed where we’re going now after having seen the way reduce fires a function against an initial value. It’s the same sort of concept, but returns two elements as an array, the current state and a dispatch function.

In other words:

const [state, dispatch] = useReducer(reducer, initialArg, init);

What’s up with that third init argument? It’s an optional value that will lazily create the initial state. That means we can calculate the initial state/value with an init function outside of the reducer instead of providing an explicit value. That’s handy if the initial value could be different, say based on a last saved state instead of a consistent value.

To get it working, we need to do a few things:

  • Define an initial state.
  • Provide a function that contains actions that update the state.
  • Trigger userReducer to dispatch an updated state that’s calculated relative to the initial state.

The classic example of this a counter application. In fact, that’s what React’s docs use to drive the concept home. Here’s that put into practice:

See the Pen
React useReducer 1
by Kingsley Silas Chijioke (@kinsomicrote)
on CodePen.

It’s a good example because it demonstrates how an initial state (a zero value) is used to calculate a new value each time an action is fired by clicking either the increase or decrease button. We could even throw in a “Reset” button in there to clear the total back to the initial state of zero.

Example: A Car Customizer

See the Pen
React useReducer – car example
by Geoff Graham (@geoffgraham)
on CodePen.

In this example, we are making the assumption that the user has selected a car to purchase. However, we want the app to allow the user to add extra options to the car. Each option has a price that adds to the base total.

First, we need to create the initial state which will consist of the car, an empty array to keep track of features, and an additional price that starts at $ 26,395 and a list of items in the store, so the user can pick what they want.

const initialState = {   additionalPrice: 0,   car: {     price: 26395,     name: "2019 Ford Mustang",     image: "https://cdn.motor1.com/images/mgl/0AN2V/s1/2019-ford-mustang-bullitt.jpg",     features: []   },   store: [     { id: 1, name: "V-6 engine", price: 1500 },     { id: 2, name: "Racing detail package", price: 1500 },     { id: 3, name: "Premium sound system", price: 500 },     { id: 4, name: "Rear spoiler", price: 250 }   ] };

Our reducer function will handle two things: the addition and removal of new items.

const reducer = (state, action) => {   switch (action.type) {     case "REMOVE_ITEM":       return {         ...state,         additionalPrice: state.additionalPrice - action.item.price,         car: { ...state.car, features: state.car.features.filter((x) => x.id !== action.item.id)},         store: [...state.store, action.item]       };     case "BUY_ITEM":       return {         ...state,         additionalPrice: state.additionalPrice + action.item.price,         car: { ...state.car, features: [...state.car.features, action.item] },         store: state.store.filter((x) => x.id !== action.item.id)       }     default:       return state;   } }

When the user selects the item she wants, we update the features for the car, increase the additionalPrice and also remove the item from the store. We ensure that the other parts of the state remain as they are.
We do something similar when a user removes an item from the features list – reduce the additional price, return the item to the store.
Here is how the App component looks like.

const App = () => {   const inputRef = useRef();   const [state, dispatch] = useReducer(reducer, initialState);      const removeFeature = (item) => {     dispatch({ type: 'REMOVE_ITEM', item });   }      const buyItem = (item) => {     dispatch({ type: 'BUY_ITEM', item })   }      return (     <div>       <div className="box">         <figure className="image is-128x128">           <img src={state.car.image} />         </figure>         <h2>{state.car.name}</h2>         <p>Amount: $  {state.car.price}</p>         <div className="content">           <h6>Extra items you bought:</h6>           {state.car.features.length ?              (               <ol type="1">                 {state.car.features.map((item) => (                   <li key={item.id}>                     <button                       onClick={() => removeFeature(item)}                       className="button">X                     </button>                     {item.name}                   </li>                 ))}               </ol>             ) : <p>You can purchase items from the store.</p>           }         </div>       </div>       <div className="box">         <div className="content">           <h4>Store:</h4>           {state.store.length ?              (             <ol type="1">               {state.store.map((item) => (                 <li key={item.id}>\                   <button                     onClick={() => buyItem(item)}                     className="button">Buy                   </button>                   {item.name}                 </li>               ))}             </ol>             ) : <p>No features</p>           }         </div>          <div className="content">         <h4>           Total Amount: $  {state.car.price + state.additionalPrice}         </h4>       </div>       </div>     </div>   ); }

The actions that get dispatched contains the details of the selected item. We make use of the action type to determine how the reducer function will handle the updating of the state. You can see that the rendered view changes based on what you do – buying an item from the store removes the item from the store and adds it to the list of features. Also, the total amount gets updated. No doubt, there are some improvements that can be done to the application, this is only for learning purpose.

What about useState? Can’t we use that instead?

An astute reader may have been asking this all along. I mean, setState is generally the same thing, right? Return a stateful value and a function to re-render a component with that new value.

const [state, setState] = useState(initialState);

We could have even used the useState() hook in the counter example provided by the React docs. However, useReducer is preferred in cases where state has to go through complicated transitions. Kent C. Dodds wrote up a explanation of the differences between the two and (while he often reaches for setState) he provides a good use case for using userReducer instead:

If your one element of your state relies on the value of another element of your state, then it’s almost always best to use useReducer

For example, imagine you have a tic-tac-toe game you’re writing. You have one element of state called squares which is just an array of all the squares and their value[.]

My rule of thumb is to reach for useReducer to handle complex states, particularly where the initial state is based on the state of other elements.

Oh wait, we already have Redux for this!

Those of you who have worked with Redux already know everything we’ve covered here and that’s because it was designed to use the Context API to pass stored states between components — without having to pass props through other components to get there.

So, does useReducer replace Redux? Nope. I mean, you can basically make your own Redux by using it with the useContext hook, but that’s doesn’t mean Redux is useless; Redux still has plenty of other features and benefits worth considering.

Where have you used userReducer? Have you found clear-cut cases where it’s better than setState? Maybe you can experiment with the things we covered here to build something. Here are a few ideas:

  • A calendar that focus at today’s date but allows a user to select other dates. Maybe even add a “Today” button that returns the user to today’s date.
  • You can try improving on the car example – have a list of cars that users can purchase. You might have to define this in the initial state, then the user can add extra features they want with a charge. These features can be predefined, or defined by the user.

The post Getting to Know the useReducer React Hook appeared first on CSS-Tricks.

CSS-Tricks

, , , ,
[Top]

Everything You Need to Know About Date in JavaScript

Date is weird in JavaScript. It gets on our nerves so much that we reach for libraries (like Date-fns and Moment) the moment (ha!) we need to work with date and time.

But we don’t always need to use libraries. Date can actually be quite simple if you know what to watch out for. In this article, I’ll walk you through everything you need to know about the Date object.

First, let’s acknowledge the existence of timezones.

Timezones

There are hundreds of timezones in our world. In JavaScript, we only care about two—Local Time and Coordinated Universal Time (UTC).

  • Local time refers to the timezone your computer is in.
  • UTC is synonymous with Greenwich Mean Time (GMT) in practice.

By default, almost every date method in JavaScript (except one) gives you a date/time in local time. You only get UTC if you specify UTC.

With this, we can talk about creating dates.

Creating a date

You can create a date with new Date(). There are four possible ways to use new Date():

  1. With a date-string
  2. With date arguments
  3. With a timestamp
  4. With no arguments

The date-string method

In the date-string method, you create a date by passing a date-string into new Date.

new Date('1988-03-21')

We tend towards the date-string method when we write dates. This is natural because we’ve been using date strings all our lives.

If I write 21-03-1988, you have no problems deducing it’s 21st of March, 1988. Yeah? But if you write 21-03-1988 in JavaScript, you get Invalid Date.

new Date('21-03-1988') returns Invalid Date.

There’s a good reason for this.

We interpret date strings differently in different parts of the world. For example 11-06-2019 is either 11th June, 2019 or 6th November 2019. But you can’t be sure which one I’m referring to, unless you know the date system I’m using.

In JavaScript, if you want to use a date string, you need to use a format that’s accepted worldwide. One of these formats is the ISO 8601 Extended format.

// ISO 8601 Extended format `YYYY-MM-DDTHH:mm:ss:sssZ`

Here’s what the values mean:

  • YYYY: 4-digit year
  • MM: 2-digit month (where January is 01 and December is 12)
  • DD: 2-digit date (0 to 31)
  • -: Date delimiters
  • T: Indicates the start of time
  • HH: 24-digit hour (0 to 23)
  • mm: Minutes (0 to 59)
  • ss: Seconds (0 to 59)
  • sss: Milliseconds (0 to 999)
  • :: Time delimiters
  • Z: If Z is present, date will be set to UTC. If Z is not present, it’ll be Local Time. (This only applies if time is provided.)

Hours, minutes, seconds and milliseconds are optional if you’re creating a date. So, if you want to create a date for , you can write this:

new Date('2019-06-11')

Pay special attention here. There’s a huge problem with creating dates with date strings. You can spot the problem if you console.log this date.

If you live in an area that’s behind GMT, you’ll get a date that says 10th June.

new Date('2019-06-11') produces 10th June if you’re in a place behind GMT.

If you live in an area that’s ahead of GMT, you’ll get a date that says 11th June.

new Date('2019-06-11') produces 11th June if you’re in a place after GMT.

This happens because the date-string method has a peculiar behavior: If you create a date (without specifying time), you get a date set in UTC.

In the above scenario, when you write new Date('2019-06-11'), you actually create a date that says 11th June, 2019, 12am UTC. This is why people who live in areas behind GMT get a 10th June instead of 11th June.

If you want to create a date in Local Time with the date-string method, you need to include the time. When you include time, you need to write the HH and mm at a minimum (or Google Chrome returns an invalid date).

new Date('2019-06-11T00:00')
Date created in Local Time vsl. Date created in UTC.

The whole Local Time vs. UTC thing with date-strings can be a possible source of error that’s hard to catch. So, I recommend you don’t create dates with date strings.

(By the way, MDN warns against the date-string approach since browsers may parse date strings differently).

MDN recommends against creating date with date strings.

If you want to create dates, use arguments or timestamps.

Creating dates with arguments

You can pass in up to seven arguments to create a date/time.

  1. Year: 4-digit year.
  2. Month: Month of the year (0-11). Month is zero-indexed. Defaults to 0 if omitted.
  3. Day: Day of the month (1-31). Defaults to 1 if omitted.
  4. Hour: Hour of the day (0-23). Defaults to 0 if omitted.
  5. Minutes: Minutes (0-59). Defaults to 0 if omitted.
  6. Seconds: Seconds (0-59). Defaults to 0 if omitted.
  7. Milliseconds: Milliseconds (0-999). Defaults to 0 if omitted.
// 11th June 2019, 5:23:59am, Local Time new Date(2019, 5, 11, 5, 23, 59)

Many developers (myself included) avoid the the arguments approach because it looks complicated. But it’s actually quite simple.

Try reading numbers from left to right. As you go left to right, you insert values in decreasing magnitude: year, month, day, hours, minutes, seconds, and milliseconds.

new Date(2017, 3, 22, 5, 23, 50)  // This date can be easily read if you follow the left-right formula. // Year: 2017, // Month: April (because month is zero-indexed) // Date: 22 // Hours: 05 // Minutes: 23 // Seconds: 50

The most problematic part with Date is that the Month value is zero-indexed, as in, January === 0, February === 1, March === 2 and so on.

We have no idea why month in JavaScript is zero-indexed, but it is. Rather than argue about why January should be 1 (and not 0), it’s better to accept that month is zero-indexed in JavaScript. Once you accept this fact, dates become much easier to work with.

Here are some more examples for you to familiarize yourself:

// 21st March 1988, 12am, Local Time. new Date(1988, 2, 21)  // 25th December 2019, 8am, Local Time. new Date(2019, 11, 25, 8)  // 6th November 2023, 2:20am, Local Time new Date(2023, 10, 6, 2, 20)  // 11th June 2019, 5:23:59am, Local Time new Date(2019, 5, 11, 5, 23, 59)

Notice dates created with arguments are all in Local Time?

That’s one of the perks of using arguments—you won’t get confused between Local Time and UTC. If you ever need UTC, you create a date in UTC this way:

// 11th June 2019, 12am, UTC. new Date(Date.UTC(2019, 5, 11))

Creating dates with timestamps

In JavaScript, a timestamp is the amount of milliseconds elapsed since 1 January 1970 (1 January 1970 is also known as Unix epoch time). From my experience, you rarely use timestamps to create dates. You only use timestamps to compare between different dates (more on this later).

// 11th June 2019, 8am (in my Local Time, Singapore) new Date(1560211200000)

With no arguments

If you create a date without any arguments, you get a date set to the current time (in Local Time).

new Date()
The time now.

You can tell from the image that it’s in Singapore when I wrote this article.

Summary about creating dates

  1. You can create date with new Date().
  2. There are four possible syntaxes:
    1. With a date string
    2. With arguments
    3. With timestamp
    4. With no arguments
  3. Never create a date with the date string method.
  4. It’s best to create dates with the arguments method.
  5. Remember (and accept) that month is zero-indexed in JavaScript.

Next, let’s talk about converting a date into a readable string.

Formatting a date

Most programming languages give you a formatting tool to create any Date format you want. For example, in PHP, you can write date("d M Y") to a date like 23 Jan 2019.

But there’s no easy way to format a date in JavaScript.

The native Date object comes with seven formatting methods. Each of these seven methods give you a specific value (and they’re quite useless).

const date = new Date(2019, 0, 23, 17, 23, 42)
  1. toString gives you Wed Jan 23 2019 17:23:42 GMT+0800 (Singapore Standard Time)
  2. toDateString gives you Wed Jan 23 2019
  3. toLocaleString gives you 23/01/2019, 17:23:42
  4. toLocaleDateString gives you 23/01/2019
  5. toGMTString gives you Wed, 23 Jan 2019 09:23:42 GMT
  6. toUTCString gives you Wed, 23 Jan 2019 09:23:42 GMT
  7. toISOString gives you 2019-01-23T09:23:42.079Z

If you need a custom format, you need to create it yourself.

Writing a custom date format

Let’s say you want something like Thu, 23 January 2019. To create this value, you need to know (and use) the date methods that comes with the Date object.

To get dates, you can use these four methods:

  1. getFullYear: Gets 4-digit year according to local time
  2. getMonth: Gets month of the year (0-11) according to local time. Month is zero-indexed.
  3. getDate: Gets day of the month (1-31) according to local time.
  4. getDay: Gets day of the week (0-6) according to local time. Day of the week begins with Sunday (0) and ends with Saturday (6).

It’s simple to create 23 and 2019 for Thu, 23 January 2019. We can use getFullYear and getDate to get them.

const d = new Date(2019, 0, 23) const year = d.getFullYear() // 2019 const date = d.getDate() // 23

It’s harder to get Thu and January.

To get January, you need to create an object that maps the value of all twelve months to their respective names.

const months = {   0: 'January',   1: 'February',   2: 'March',   3: 'April',   4: 'May',   5: 'June',   6: 'July',   7: 'August',   8: 'September',   9: 'October',   10: 'November',   11: 'December' }

Since Month is zero-indexed, we can use an array instead of an object. It produces the same results.

const months = [   'January',   'February',   'March',   'April',   'May',   'June',   'July',   'August',   'September',   'October',   'November',   'December' ]

To get January, you need to:

  1. Use getMonth to get the zero-indexed month from the date.
  2. Get the month name from months
const monthIndex = d.getMonth() const monthName = months(monthIndex) console.log(monthName) // January

The condensed version:

const monthName = months(d.getMonth()) console.log(monthName) // January

You do the same thing to get Thu. This time, you need an array that contains seven days of the week.

const days = [   'Sun',   'Mon',   'Tue',   'Wed',   'Thu',   'Fri',   'Sat' ]

Then you:

  1. Get dayIndex with getDay
  2. Use dayIndex to get dayName
const dayIndex = d.getDay() const dayName = days[dayIndex] // Thu

Short version:

const dayName = days[d.getDay()] // Thu

Then, you combine all the variables you created to get the formatted string.

const formatted = `$ {dayName}, $ {date} $ {monthName} $ {year}` console.log(formatted) // Thu, 23 January 2019

Yes, it tedious. But it’s not impossible once you get the hang of it.

If you ever need to create a custom-formatted time, you can use the following methods:

  1. getHours: Gets hours (0-23) according to local time.
  2. getMinutes: Gets minutes (0-59) according to local time.
  3. getSeconds: Gets seconds (0-59) according to local time.
  4. getMilliseconds: Gets milliseconds (0-999) according to local time.

Next, let’s talk about comparing dates.

Comparing dates

If you want to know whether a date comes before or after another date, you can compare them directly with >, <, >= and <=.

const earlier = new Date(2019, 0, 26) const later = new Date(2019, 0, 27)  console.log(earlier < later) // true

It’s more difficult if you want to check if two dates fall exactly at the same time. You can’t compared them with == or ===.

const a = new Date(2019, 0, 26) const b = new Date(2019, 0, 26)  console.log(a == b) // false console.log(a === b) // false

To check whether two dates fall exactly at the same time, you can check their timestamps with getTime.

const isSameTime = (a, b) => {   return a.getTime() === b.getTime() }  const a = new Date(2019, 0, 26) const b = new Date(2019, 0, 26) console.log(isSameTime(a, b)) // true

If you want to check whether two dates fall on the same day, you can check their getFullYear, getMonth and getDate values.

const isSameDay = (a, b) => {   return a.getFullYear() === b.getFullYear() &&     a.getMonth() === b.getMonth() &&     a.getDate()=== b.getDate() }  const a = new Date(2019, 0, 26, 10) // 26 Jan 2019, 10am const b = new Date(2019, 0, 26, 12) // 26 Jan 2019, 12pm console.log(isSameDay(a, b)) // true

There’s one final thing we have to cover.

Getting a date from another date

There are two possible scenarios where you want to get a date from another date.

  1. Set a specific date/time value from another date.
  2. Add/subtract a delta from another date.

Setting a specific date/time

You can use these methods to set a date/time from another date:

  1. setFullYear: Set 4-digit year in Local Time.
  2. setMonth: Set month of the year in Local Time.
  3. setDate: Set day of the month in Local Time.
  4. setHours: Set hours in Local Time.
  5. setMinutes: Set minutes in Local Time.
  6. setSeconds: Set seconds in Local Time.
  7. setMilliseconds: Set milliseconds in Local Time.

For example, if you want to set a date to the 15th of the month, you can use setDate(15).

const d = new Date(2019, 0, 10) d.setDate(15)  console.log(d) // 15 January 2019

If you want to set the month to June, you can use setMonth. (Remember, month in JavaScript is zero-indexed!)

const d = new Date(2019, 0, 10) d.setMonth(5)  console.log(d) // 10 June 2019

Note: The setter methods above mutate the original date object. In practice, we should not mutate objects (more on why here). We should perform these operations on a new date object instead.

const d = new Date(2019, 0, 10) const newDate = new Date(d) newDate.setMonth(5)  console.log(d) // 10 January 2019 console.log(newDate) // 10 June 2019

Adding/Subtracting delta from another date

A delta is a change. By adding/subtracting delta from another date, I mean this: You want to get a date that’s X from another date. It can be X year, X month, X day, etc.

To get a delta, you need to know the current date’s value. You can get it using these methods:

  1. getFullYear: Gets 4-digit year according to local time
  2. getMonth: Gets month of the year (0-11) according to local time.
  3. getDate: Gets day of the month (1-31) according to local time.
  4. getHours: Gets hours (0-23) according to local time.
  5. getMinutes: Gets minutes (0-59) according to local time.
  6. getSeconds: Gets seconds (0-59) according to local time.
  7. getMilliseconds: Gets milliseconds (0-999) according to local time.

There are two general approaches to add/subtract a delta. The first approach is more popular on Stack Overflow. It’s concise, but harder to grasp. The second approach is more verbose, but easier to understand.

Let’s go through both approaches.

Say you want to get a date that’s three days from today. For this example, let’s also assume today is . (It’s easier to explain when we’re working with a fixed date).

The first approach (the set approach)
// Assumes today is 28 March 2019 const today = new Date(2019, 2, 28)

First, we create a new Date object (so we don’t mutate the original date)

const finalDate = new Date(today)

Next, we need to know the value we want to change. Since we’re changing days, we can get the day with getDate.

const currentDate = today.getDate()

We want a date that’s three days from today. We’ll use add the delta (3) to the current date.

finalDate.setDate(currentDate + 3)

Full code for the set approach:

const today = new Date(2019, 2, 28) const finalDate = new Date(today) finalDate.setDate(today.getDate() + 3)  console.log(finalDate) // 31 March 2019
The second approach (the new Date approach)

Here, we use getFullYear, getMonth, getDate and other getter methods until we hit the type of value we want to change. Then, we use create the final date with new Date.

const today = new Date(2019, 2, 28)  // Getting required values const year = today.getFullYear() const month = today.getMonh() const day = today.getDate()  // Creating a new Date (with the delta) const finalDate = new Date(year, month, day + 3)  console.log(finalDate) // 31 March 2019

Both approaches work. Choose one and stick with it.

Automatic date correction

If you provide Date with a value that’s outside of its acceptable range, JavaScript recalculates the date for you automatically.

Here’s an example. Let’s say we set date to . (There’s no 33rd March on the calendar). In this case, JavaScript adjusts 33rd March to 2nd April automatically.

// 33rd March => 2nd April new Date(2019, 2, 33)
33rd March gets converted to 2nd April automatically.

This means you don’t need to worry about calculating minutes, hours, days, months, etc. when creating a delta. JavaScript handles it for you automatically.

// 33rd March => 2nd April new Date(2019, 2, 30 + 3)
30 + 3 = 33. 33rd March gets converted to 2nd April automatically.

And that’s everything you need to know about JavaScript’s native Date object.

Interested to learn more JavaScript?

If you found this intro to Date useful, you might love Learn JavaScript, a course I created to teach people everything they need to know about JavaScript.

In the course, I cover the basic concepts of what you need to know, then I show you how to use the concepts you learned to build real-world components.

Have a look. You might find it helpful.

In the meantime, if you have any JavaScript questions, feel free to contact me. I’ll do by best to create free articles to answer your questions.

The post Everything You Need to Know About Date in JavaScript appeared first on CSS-Tricks.

CSS-Tricks

, , , , ,
[Top]

Everything You Ever Wanted to Know About inputmode

The inputmode global attribute provides a hint to browsers for devices with onscreen keyboards to help them decide which keyboard to display when a user has selected any input or textarea element.

<input type="text" inputmode="" /> <textarea inputmode="" />

Unlike changing the type of the form, inputmode doesn’t change the way the browser interprets the input — it instructs the browser which keyboard to display.

The inputmode attribute has a long history but has only very recently been adopted by the two major mobile browsers: Safari for iOS and Chrome for Android. Before that, it was implemented in Firefox for Android way back in 2012, and then subsequently removed several months later (though it is still available via a flag).

Almost six years later, Chrome for Android implemented the feature — and with the recent release of iOS 12.2, Safari now supports it too.

This browser support data is from Caniuse, which has more detail. A number indicates that browser supports the feature at that version and up.

Desktop

Chrome Opera Firefox IE Edge Safari
66 53 20 No 75 No

Mobile / Tablet

iOS Safari Opera Mobile Opera Mini Android Android Chrome Android Firefox
12.2 No No 67 74 No

But before we go deep into the ins and outs of the attribute, consider that the WHATWG living standard provides inputmode documentation while the W3C 5.2 spec no longer lists it in its contents, which suggests they consider it obsolete. Given that WHATWG has documented it and browsers have worked toward supporting it, we’re going to go assume WHATWG specifications are the standard.

inputmode accepts a number of values. Let’s go through them, one by one.

None

<input type="text" inputmode="none" />

We’re starting here because it’s very possible we don’t want any type of keyboard on an input. Using inputmode=none will not show a keyboard at all on Chrome for Android. iOS 12.2 will still show its default alphanumeric keyboard, so specifying none could be sort of a reset for iOS in that regard. Regardless, none is intended for content that renders its own keyboard control.

Numeric

<input type="text" inputmode="numeric" />

This one is probably the one of the more common inputmode values out in the wild because it’s ideal for inputs that require numbers but no letters — things like PIN entry, zip codes, credit card numbers, etc. Using the numeric value with an input of type="text" may actually make more sense than setting the input to type="number" alone because, unlike a numeric input, inputmode="numeric" can be used with maxlength, minlength and pattern attributes, making it more versatile for different use cases.

The numeric value on Chrome Android (left) and iOS 12.2 (right)

I’ve often seen sites using type=tel on an input to display a numeric keyboard, and that checks out as a workaround, but isn’t semantically correct. If that bums you out, remember that inputmode supports patterns, we can add pattern="d*" to the input for the same effect. That said, only use this if you are certain the input should only allow numeric input because Android (unlike iOS) doesn’t allow the user to change to the keyboard to use letters, which might inadvertently prevent users from submitting valid data.

Tel

<input type="text" inputmode="tel" />

Entering a telephone number using a standard alphanumeric keyboard can be a pain. For one, each number on a telephone keyboard (except 1 and 0) represents three letters (e.g. 2 represents A, B and C) which are displayed with the number. The alphanumeric keyboard does not reference those letters, so decoding a telephone number containing letters (e.g. 1-800-COLLECT) takes more mental power.

The tel value on Chrome Android (left) and iOS 12.2 (right)

Using inputmode set to tel will produce a standard-looking telephone keyboard, including keys for digits 0 to 9, the pound (#) character, and the asterisk (*) character. Plus, we get those alphabetic mnemonic labels (e.g. ABC).

Decimal

<input type="text" inputmode="decimal" />
The decimal value on Chrome Android (left) and iOS 12.2 (right)

An inputmode set to the decimal value results in a subtle change in iOS where the keyboard appears to be exactly the same as the tel value, but replaces the +*# key with a simple decimal (.). On the flip side, this has no effect on Android, which will simply use the numeric keyboard.

Email

<input type="text" inputmode="email" />

I’m sure you (and at least someone you know) has filled out a form that asks for an email address, only to make you swap keyboards to access the @ character. It’s not life-threatening or anything, but certainly not a great user experience either.

That’s where the email value comes in. It brings the @ character into the fray, as well as the decimal (.) character.

The email value on Chrome Android (left) and iOS 12.2 (right)

This could also be a useful keyboard to show users who need to enter a Twitter username, given that@ is a core Twitter character for identifying users. However, the email address suggestions that iOS display above the keyboard may cause confusion.

Another use case could be if you have your own email validation script and don’t want to use the browsers built-in email validation.

URL

<input type="text" inputmode="url" />
The url value on Chrome Android (left) and iOS 12.2 (right)

The url value provides a handy shortcut for users to append TLDs (e.g. .com or .co.uk) with a single key, as well keys typically used in web addresses, like the dot (.) and forward slash (/) characters. The exact TLD displayed on the keyboard is tied to the user’s locale.

This could also be a useful keyboard to show users if your input accepts domain names (e.g. css-tricks.com) as well as full URIs (e.g. https://css-tricks.com). Use type="url" instead if your input requires validating the input.

Search

<input type="text" inputmode="search" />
The search value on Chrome Android (left) and iOS 12.2 (right)

This displays a blue Go key on iOS and a green Enter key on Android, both in place of where Return. As you may have guessed by the value’s name, search is useful for search forms, providing that submission key to make a query.

If you’d like to showSearch instead of Enter on iOS and a magnifying glass icon on Android in place of the green arrow, use type=search instead.

Other things you oughta know

  • Chromium-based browsers on Android — such as Microsoft Edge, Brave and Opera — share the same inputmode behavior as Chrome.
  • I haven’t included details of keyboards on iPad for the sake of brevity. It’s mostly the same as iPhone but includes more keys. Same is true for Android tablets, save for third-party keyboards, which might be another topic worth covering.
  • The original proposed spec had the values kana and katakana for Japanese input but they were never implemented by any browser and have since been removed from the spec.
  • latin-name was also one of the values of the original spec and has since been removed. Interestingly, if it’s used now on Safari for iOS, it will display the user’s name as a suggestion above the keyboard.

    The latin-name value displays my name as an auto-fill suggestion

Demo

Oh, you want to see how all of these input modes work for yourself? Here’s a demo you can use on a device with a touchscreen keyboard to see the differences.

References

, , , , ,
[Top]

Getting To Know The MutationObserver API

MutationObserver watches the DOM, specifically the places you tell it to, like:

document.querySelector('#watch-this');

…and it can tell you (trigger a callback) when stuff happens — like when a child is added, removed, changed, or a number of other things.

I used it just the other day to watch the <head> of a Pen and detected newly-injected processed Sass code, so you could use CodePen to see Sass and CSS side by side:

See the Pen
Sassmeister clone
by Chris Coyier (@chriscoyier)
on CodePen.

Direct Link to ArticlePermalink

The post Getting To Know The MutationObserver API appeared first on CSS-Tricks.

CSS-Tricks

, ,
[Top]

A Few Functional Uses for Intersection Observer to Know When an Element is in View

You might not know this, but JavaScript has stealthily accumulated quite a number of observers in recent times, and Intersection Observer is a part of that arsenal. Observers are objects that spot something in real-time — like birdwatchers going to their favorite place to sit and wait for the birds to come.

Different observers observe different things (not everyone watches hawks).

The very first observer I came to know was the Mutation Observer that looks for changes to the DOM tree. It was a one-of-a-kind at the time, but now we have many more observers.

Intersection Observer observes the “intersection” (i.e. the passing across) of an element through one of its ancestor elements or the area on screen where the page is visible (aka the viewport).

It’s sort of like watching a train pass through a station. You can see when the train comes in, when it leaves, and how long it was stationary.

Knowing when an element is about to come into view, if it has gone out of view, or how long it’s been since it came into view all have useful applications. So, we’ll see some of those use cases now — right after seeing the code for creating an IntersectionObserver object by way of the Intersection Observer API.

A quick overview of IntersectionObserver

The Intersection Observer API has already gained wide support at the time of this writing.

This browser support data is from Caniuse, which has more detail. A number indicates that browser supports the feature at that version and up.

Desktop

Chrome Opera Firefox IE Edge Safari
58 45 55 No 16 12.1

Mobile / Tablet

iOS Safari Opera Mobile Opera Mini Android Android Chrome Android Firefox
12.2 46 No 67 74 66

But if you want to check whether Intersection Observer is supported while you’re working with it, you could see if the property IntersectionObserver exists in the window object:

if(!!window.IntersectionObserver){} /* or */ if('IntersectionObserver' in window){}

OK, now for a look at the object creation:

var observer = new IntersectionObserver(callback, options);

The IntersectionObserver object’s constructor takes two parameters. The first one is a callback function that’s executed once the observer notices an intersection and has asynchronously delivered some data about that intersection.

The second (optional) parameter is options, an object with information to define what’s going to be the “intersection.” We may not want to know when an element is about to come into view, but only when it’s fully visible. Something like that is defined through the options parameter.

Options has three properties:

  • root – The ancestor element/viewport that the observed element will intersect. Think of it as the train station that the train will intersect.
  • rootMargin – A perimeter of the root element, shrinking or growing the root element’s area to watch out for intersection. It’s similar to the CSS margin property.
  • threshold – An array of values (between 0 and 1.0), each representing the distance an element has intersected into or crossed over in the root at which the callback is to be triggered.

Let’s say our threshold is 0.5. The callback is triggered when the element is in or passes its half-visible threshold. If the value is [0.3, 0.6], then the callback is triggered when the element is in or passes its 30% visible threshold and also, its 60% visible threshold.

That’s enough of the theory now. Let’s see some demos. First up, lazy loading.

Use Case 1: Lazy loading images

See the Pen
Intersection Observer – Lazy Load
by Preethi Sam (@rpsthecoder)
on CodePen.

To see the loading at the mark, view this webpage since the embedded demo doesn’t show that.

CSS-Tricks has thoroughly covered lazy loading in before and it’s typically done like this: display a lightweight placeholder where images are intended, then swap them out for the intended images as they come (or are about to come) into view. Believe me, there’s nothing lazy about implementing this — that is, until we get something native to work with.

We’ll apply the same mechanics. First, we’ve a bunch of images and have defined a placeholder image to display initially. We’re using a data attribute carrying the URL of the original image to be shown that defines the actual image to load when it comes into view.

<img src="placeholder.png" data-src="img-1.jpg"> <img src="placeholder.png" data-src="img-2.jpg"> <img src="placeholder.png" data-src="img-3.jpg"> <!-- more images -->

The rest is scripting.

let observer = new IntersectionObserver( (entries, observer) => {    entries.forEach(entry => {     /* Here's where we deal with every intersection */   }); },  {rootMargin: "0px 0px -200px 0px"});

The callback function above is an arrow function (though you can use a normal function instead).

The callback function receives two parameters: a set of entries carrying the information about each intersection and the observer itself. Those entries can be filtered or looped through so we can then deal with the intersection entries that we want. As for the options, I’ve only provided the rootMargin value, letting the root and threshold properties fall into their default values.

The root default is the viewport and threshold default is 0 — which can be roughly translated to “ping me the very moment that the element appears in the viewport!”

The oddity, though, is that I reduced the viewport’s observation area by two hundred pixels at the bottom using rootMargin. We wouldn’t typically do this for lazy loading. Instead, we might increase the margin or let it default. But reducing isn’t something we would usually do in this situation. I did it only because I want to demonstrate the original images loading at the threshold in the observed area. Otherwise, all the action would happen out of view.

When the image intersects the viewport’s observer area (which is 200px above the bottom in the demo), we replace the placeholder image with the actual image.

let observer = new IntersectionObserver( (entries, observer) => {  entries.forEach(entry => {     /* Placeholder replacement */     entry.target.src = entry.target.dataset.src;     observer.unobserve(entry.target);   }); },  {rootMargin: "0px 0px -200px 0px"});

entry.target is the element observed by the observer. In our case, those are the image elements. Once the placeholder is replaced in an image element, we don’t have to observe it anymore, so we call the observer’s unobserve method for it.

Now that the observer is ready, it’s time to start observing all the images by using its observer method:

document.querySelectorAll('img').forEach(img => { observer.observe(img) });

That’s it! we’ve lazy loaded the images. Onto the next demo.

Use Case 2: Auto-pause video when it’s out of view

Let’s say we’re watching a video on YouTube and (for whatever reason) we want to scroll down to read the comments. I don’t know about you, but I don’t usually pause the video first before doing that, which means I miss some of the video while I’m browsing.

Wouldn’t it be nice if the video paused for us when we scroll away from it? It would be even nicer if the video resumed when it’s back in view so there’s no need to hit Play or Pause at all.

Intersection Observer can certainly do that.

See the Pen
IntersectionObserver: auto-pause out of view video
by Preethi Sam (@rpsthecoder)
on CodePen.

Here’s our video in the HTML:

<video src="OSRO-animation.mp4" controls=""></video>

Here’s how we toggle between play and pause:

let video = document.querySelector('video'); let isPaused = false; /* Flag for auto-paused video */ let observer = new IntersectionObserver((entries, observer) => {    entries.forEach(entry => {     if(entry.intersectionRatio!=1  && !video.paused){       video.pause(); isPaused = true;     }     else if(isPaused) {video.play(); isPaused=false}   }); }, {threshold: 1}); observer.observe(video);

Before I show you how we’re pausing and playing the video during each intersection (i.e. entry), I want to bring your attention to the threshold property of the options.

Th threshold has a value of 1. Both root and rootMargin will default. This is the same as saying, “hey, let me know as soon the element is fully visible on the viewport.”

Once the intersection happens and the callback is triggered, we pause or play the video based on this logic:

A flow chart for toggling play and pause on a video, where if video not fully visible and not paused, then isPaused is true. But if video was auto-paused, then IsPaused is false.

I have not called unobserve for the video, so the observer keeps observing the video and pauses every time it goes out of view.

Use Case 3: See how much content is viewed

This can be interpreted and implemented in many ways depending on what your content is and the way you prefer to measure how much of it has been viewed.

For a simple example, we’ll observe the last paragraph of every article in a list of articles on a page. Once an article’s last paragraph becomes fully visible, we will consider that article read — like how we might say that seeing the last coach of a train counts as having seen the whole train.

Here’s a demo that shows two articles on a page, each containing a number of paragraphs.

See the Pen
IntersectionObsever: content viewed
by Preethi Sam (@rpsthecoder)
on CodePen.

Our simplified HTML is something like this:

<div id="count"><!-- The place where "number of articles viewed" is displayed --></div>  <h2>Article 1</h2> <article>   <p><!-- Content --></p>   <!-- More paragraphs --> </article> <h2>Article 2</h2> <article>   <p><!-- Content --></p>   <!-- More paragraphs --> </article> <!-- And so on... -->
let n=0; /* Total number of articles viewed */ let count = document.querySelector('#count'); let observer = new IntersectionObserver((entries, observer) => {    entries.forEach(entry => {     if(entry.isIntersecting){       count.textContent= `articles fully viewed - $ {++n}`;        observer.unobserve(entry.target);     }   }); }, {threshold: 1});  document.querySelectorAll('article > p:last-child').forEach(p => { observer.observe(p) });

During each intersection — the full view of the last paragraph of an article — we’re incrementing a count: n, that represents the total number of articles read. Then we display that number above the list of articles.

Once we’ve counted in an intersection of the last paragraph, it doesn’t need to be observed anymore, so we call unobserve for it.

Thanks for observing along!

That’s it for the examples we’re going to look at together for this post. You probably get the idea of how using it is, to be able to observe elements and trigger events based on where they intersect the viewport.

That said, it’s worth using caution when making visual changes based on the intersection data obtained through the observer. Sure, Intersection Observer is hassle free when it comes to logging intersection data. But when it’s being used to make onscreen changes, we need to ensure the changes aren’t lagging, which is a possibility because we’re basically making changes based on data retrieved asynchronously. That might require a little bit of time to load.

As we saw, each intersection entry has a set of properties conveying information about the intersection. I didn’t cover all of them in this post, so be sure to review them.

The post A Few Functional Uses for Intersection Observer to Know When an Element is in View appeared first on CSS-Tricks.

CSS-Tricks

, , , , , ,
[Top]

7 things you should know when getting started with Serverless APIs

I want you to take a second and think about Twitter, and think about it in terms of scale. Twitter has 326 million users. Collectively, we create ~6,000 tweets every second. Every minute, that’s 360,000 tweets created. That sums up to nearly 200 billion tweets a year. Now, what if the creators of Twitter had been paralyzed by how to scale and they didn’t even begin?

That’s me on every single startup idea I’ve ever had, which is why I love serverless so much: it handles the issues of scaling leaving me to build the next Twitter!

Live metrics with Application Insights

As you can see in the above, we scaled from one to seven servers in a matter of seconds, as more user requests come in. You can scale that easily, too.

So let’s build an API that will scale instantly as more and more users come in and our workload increases. We’re going to do that is by answering the following questions:


How do I create a new serverless project?

With every new technology, we need to figure out what tools are available for us and how we can integrate them into our existing tool set. When getting started with serverless, we have a few options to consider.

First, we can use the good old browser to create, write and test functions. It’s powerful, and it enables us to code wherever we are; all we need is a computer and a browser running. The browser is a good starting point for writing our very first serverless function.

Serverless in the browser

Next, as you get more accustomed to the new concepts and become more productive, you might want to use your local environment to continue with your development. Typically you’ll want support for a few things:

  • Writing code in your editor of choice
  • Tools that do the heavy lifting and generate the boilerplate code for you
  • Run and debug code locally
  • Support for quickly deploying your code

Microsoft is my employer and I’ve mostly built serverless applications using Azure Functions so for the rest of this article I’ll continue using them as an example. With Azure Functions, you’ll have support for all these features when working with the Azure Functions Core Tools which you can install from npm.

npm install -g azure-functions-core-tools

Next, we can initialize a new project and create new functions using the interactive CLI:

func CLI

If your editor of choice happens to be VS Code, then you can use it to write serverless code too. There’s actually a great extension for it.

Once installed, a new icon will be added to the left-hand sidebar — this is where we can access all our Azure-related extensions! All related functions can to be grouped under the same project (also known as a function app). This is like a folder for grouping functions that should scale together and that we want to manage and monitor at the same time. To initialize a new project using VS Code, click on the Azure icon and then the folder icon.

Create new Azure Functions project

This will generate a few files that help us with global settings. Let’s go over those now.

host.json

We can configure global options for all functions in the project directly in the host.json file.

In it, our function app is configured to use the latest version of the serverless runtime (currently 2.0). We also configure functions to timeout after ten minutes by setting the functionTimeout property to 00:10:00 — the default value for that is currently five minutes (00:05:00).

In some cases, we might want to control the route prefix for our URLs or even tweak settings, like the number of concurrent requests. Azure Functions even allows us to customize other features like logging, healthMonitor and different types of extensions.

Here’s an example of how I’ve configured the file:

// host.json {   "version": "2.0",   "functionTimeout": "00:10:00",   "extensions": {   "http": {     "routePrefix": "tacos",     "maxOutstandingRequests": 200,     "maxConcurrentRequests": 100,     "dynamicThrottlesEnabled": true   } } }

Application settings

Application settings are global settings for managing runtime, language and version, connection strings, read/write access, and ZIP deployment, among others. Some are settings that are required by the platform, like FUNCTIONS_WORKER_RUNTIME, but we can also define custom settings that we’ll use in our application code, like DB_CONN which we can use to connect to a database instance.

While developing locally, we define these settings in a file named local.settings.json and we access them like any other environment variable.

Again, here’s an example snippet that connects these points:

// local.settings.json {   "IsEncrypted": false,   "Values": {     "AzureWebJobsStorage": "your_key_here",     "FUNCTIONS_WORKER_RUNTIME": "node",     "WEBSITE_NODE_DEFAULT_VERSION": "8.11.1",     "FUNCTIONS_EXTENSION_VERSION": "~2",     "APPINSIGHTS_INSTRUMENTATIONKEY": "your_key_here",     "DB_CONN": "your_key_here",   } }

Azure Functions Proxies

Azure Functions Proxies are implemented in the proxies.json file, and they enable us to expose multiple function apps under the same API, as well as modify requests and responses. In the code below we’re publishing two different endpoints under the same URL.

// proxies.json {   "$ schema": "http://json.schemastore.org/proxies",   "proxies": {     "read-recipes": {         "matchCondition": {         "methods": ["POST"],         "route": "/api/recipes"       },       "backendUri": "https://tacofancy.azurewebsites.net/api/recipes"     },     "subscribe": {       "matchCondition": {         "methods": ["POST"],         "route": "/api/subscribe"       },       "backendUri": "https://tacofancy-users.azurewebsites.net/api/subscriptions"     }   } }

Create a new function by clicking the thunder icon in the extension.

Create a new Azure Function

The extension will use predefined templates to generate code, based on the selections we made — language, function type, and authorization level.

We use function.json to configure what type of events our function listens to and optionally to bind to specific data sources. Our code runs in response to specific triggers which can be of type HTTP when we react to HTTP requests — when we run code in response to a file being uploaded to a storage account. Other commonly used triggers can be of type queue, to process a message uploaded on a queue or time triggers to run code at specified time intervals. Function bindings are used to read and write data to data sources or services like databases or send emails.

Here, we can see that our function is listening to HTTP requests and we get access to the actual request through the object named req.

// function.json {   "disabled": false,   "bindings": [     {       "authLevel": "anonymous",       "type": "httpTrigger",       "direction": "in",       "name": "req",       "methods": ["get"],       "route": "recipes"     },     {       "type": "http",       "direction": "out",       "name": "res"     }   ] }

index.js is where we implement the code for our function. We have access to the context object, which we use to communicate to the serverless runtime. We can do things like log information, set the response for our function as well as read and write data from the bindings object. Sometimes, our function app will have multiple functions that depend on the same code (i.e. database connections) and it’s good practice to extract that code into a separate file to reduce code duplication.

//Index.js module.exports = async function (context, req) {   context.log('JavaScript HTTP trigger function processed a request.');    if (req.query.name || (req.body && req.body.name)) {       context.res = {           // status: 200, /* Defaults to 200 */           body: "Hello " + (req.query.name || req.body.name)       };   }   else {       context.res = {           status: 400,           body: "Please pass a name on the query string or in the request body"       };   } };

Who’s excited to give this a run?

How do I run and debug Serverless functions locally?

When using VS Code, the Azure Functions extension gives us a lot of the setup that we need to run and debug serverless functions locally. When we created a new project using it, a .vscode folder was automatically created for us, and this is where all the debugging configuration is contained. To debug our new function, we can use the Command Palette (Ctrl+Shift+P) by filtering on Debug: Select and Start Debugging, or typing debug.

Debugging Serverless Functions

One of the reasons why this is possible is because the Azure Functions runtime is open-source and installed locally on our machine when installing the azure-core-tools package.

How do I install dependencies?

Chances are you already know the answer to this, if you’ve worked with Node.js. Like in any other Node.js project, we first need to create a package.json file in the root folder of the project. That can done by running npm init -y — the -y will initialize the file with default configuration.

Then we install dependencies using npm as we would normally do in any other project. For this project, let’s go ahead and install the MongoDB package from npm by running:

npm i mongodb

The package will now be available to import in all the functions in the function app.

How do I connect to third-party services?

Serverless functions are quite powerful, enabling us to write custom code that reacts to events. But code on its own doesn’t help much when building complex applications. The real power comes from easy integration with third-party services and tools.

So, how do we connect and read data from a database? Using the MongoDB client, we’ll read data from an Azure Cosmos DB instance I have created in Azure, but you can do this with any other MongoDB database.

//Index.js const MongoClient = require('mongodb').MongoClient;  // Initialize authentication details required for database connection const auth = {   user: process.env.user,   password: process.env.password };  // Initialize global variable to store database connection for reuse in future calls let db = null; const loadDB = async () => {   // If database client exists, reuse it     if (db) {     return db;   }   // Otherwise, create new connection     const client = await MongoClient.connect(     process.env.url,     {       auth: auth     }   );   // Select tacos database   db = client.db('tacos');   return db; };  module.exports = async function(context, req) {   try {     // Get database connection     const database = await loadDB();     // Retrieve all items in the Recipes collection      let recipes = await database       .collection('Recipes')       .find()       .toArray();     // Return a JSON object with the array of recipes      context.res = {       body: { items: recipes }     };   } catch (error) {     context.log(`Error code: $ {error.code} message: $ {error.message}`);     // Return an error message and Internal Server Error status code     context.res = {       status: 500,       body: { message: 'An error has occurred, please try again later.' }     };   } };

One thing to note here is that we’re reusing our database connection rather than creating a new one for each subsequent call to our function. This shaves off ~300ms of every subsequent function call. I call that a win!

Where can I save connection strings?

When developing locally, we can store our environment variables, connection strings, and really anything that’s secret into the local.settings.json file, then access it all in the usual manner, using process.env.yourVariableName.

local.settings.json {   "IsEncrypted": false,   "Values": {     "AzureWebJobsStorage": "",     "FUNCTIONS_WORKER_RUNTIME": "node",     "user": "your-db-user",     "password": "your-db-password",     "url": "mongodb://your-db-user.documents.azure.com:10255/?ssl=true"   } }

In production, we can configure the application settings on the function’s page in the Azure portal.

However, another neat way to do this is through the VS Code extension. Without leaving your IDE, we can add new settings, delete existing ones or upload/download them to the cloud.

Debugging Serverless Functions

How do I customize the URL path?

With the REST API, there are a couple of best practices around the format of the URL itself. The one I settled on for our Recipes API is:

  • GET /recipes: Retrieves a list of recipes
  • GET /recipes/1: Retrieves a specific recipe
  • POST /recipes: Creates a new recipe
  • PUT /recipes/1: Updates recipe with ID 1
  • DELETE /recipes/1: Deletes recipe with ID 1

The URL that is made available by default when creating a new function is of the form http://host:port/api/function-name. To customize the URL path and the method that we listen to, we need to configure them in our function.json file:

// function.json {   "disabled": false,   "bindings": [     {       "authLevel": "anonymous",       "type": "httpTrigger",       "direction": "in",       "name": "req",       "methods": ["get"],       "route": "recipes"     },     {       "type": "http",       "direction": "out",       "name": "res"     }   ] }

Moreover, we can add parameters to our function’s route by using curly braces: route: recipes/{id}. We can then read the ID parameter in our code from the req object:

const recipeId = req.params.id;

How can I deploy to the cloud?

Congratulations, you’ve made it to the last step! 🎉 Time to push this goodness to the cloud. As always, the VS Code extension has your back. All it really takes is a single right-click we’re pretty much done.

Deployment using VS Code

The extension will ZIP up the code with the Node modules and push them all to the cloud.

While this option is great when testing our own code or maybe when working on a small project, it’s easy to overwrite someone else’s changes by accident — or even worse, your own.

Don’t let friends right-click deploy!
— every DevOps engineer out there

A much healthier option is setting up on GitHub deployment which can be done in a couple of steps in the Azure portal, via the Deployment Center tab.

Github deployment

Are you ready to make Serverless APIs?

This has been a thorough introduction to the world of Servless APIs. However, there’s much, much more than what we’ve covered here. Serverless enables us to solve problems creatively and at a fraction of the cost we usually pay for using traditional platforms.

Chris has mentioned it in other posts here on CSS-Tricks, but he created this excellent website where you can learn more about serverless and find both ideas and resources for things you can build with it. Definitely check it out and let me know if you have other tips or advice scaling with serverless.

The post 7 things you should know when getting started with Serverless APIs appeared first on CSS-Tricks.

CSS-Tricks

, , , , , ,
[Top]

Did you know that CSS Custom Properties can handle images too?

So you might be aware of CSS Custom Properties that let you set a variable, such as a theme color, and then apply it to multiple classes like this:

:root {   --theme: #777; }  .alert {   background: var(—-theme); }  .button {   background: var(—-theme); }

Well, I had seen this pattern so often that I thought Custom Properties could only be used for color values like rgba or hex – although that’s certainly not the case! After a little bit of experimentation and sleuthing around, I realized that it’s possible to use Custom Properties to set image paths, too.

Here’s an example of that in action:

:root {   --errorIcon: url(error.svg) }  .alert {   background-image: var(--errorIcon); }  .form-error {   background-image: var(--errorIcon); }

Kinda neat, huh? I think this could be used to make an icon system where you could define a whole list of images in the :root and call it whenever you needed to. Or you could make it easier to theme certain classes based on their state or perhaps in a media query, as well. Remember, too, that custom properties can be overridden within an element:

:root {   --alertIcon: url(alert-icon.svg) }  .alert {   background-image: var(--alertIcon); }  .form-error {   --alertIcon: url(alert-icon-error.svg)   background-image: var(--alertIcon); }

And, considering that custom properties are selectable in JavaScript, think about the possibilities of swapping out images as well. I reckon this might useful to know!

The post Did you know that CSS Custom Properties can handle images too? appeared first on CSS-Tricks.

CSS-Tricks

, , , ,
[Top]