So now with all these things we learned about browser support and how to determine the correct support
level,
let's learn about some strategies on how you can build a web application that works in a broad variety
of browsers
and there, one thing we could do is we could use feature detection and provide fallbacks if a certain
feature is not available or not supported by a browser.
Let's say we want to use the clipboard API,
that's a relatively modern browser API that allows us to interact with the user's clipboard,
so the thing you use with copy and pasting. If we search for clipboard API and we check the MDN
article and we scroll down, we see browser support is not looking that great.
It works on FIrefox and Chrome,
we don't know whether it works in Safari,
it does not work in Edge and not in Internet Explorer.
Now let's also check
caniuse.com,
let's search for a clipboard there
and there if we scroll down a bit, here to the clipboard API, we see the same picture. For Safari
it's simply not clear whether it's supported but we definitely know it's not supported in Edge or Internet
Explorer,
now in Chrome and FIrefox however it does work.
Now how can it be not clear for Safari?
Well it's not about people not testing it there,
it is about how the browser vendors,
so the people working on Safari, how they communicate features they want to support and if they haven't
communicated any information regarding their plans on whether they want to support the clipboard API
or not, then this is treated as unknown,
we don't know what their plans are we don't know if they're about to implement it, if it should be working
and it's not working due to a bug or anything like that.
So this could be a reason for this feature being unknown
rather than being marked as not supported. Now this also is a feature that might be nice to have in an application
to simplify some process for the user for example but that's not a must-have,
so therefore here we could use feature detection and then simply provide two routes. We can check if
the feature is available and I will of course show you how that works and if it is available, we execute
the code that relies on this feature to exist,
otherwise if it's not available, we execute some fallback code or we show an error message to the
user, we give the user another way of letting him use our application.
So basically what we try to do is we want avoid that the application crashes and instead just provide
two different code branches that can execute based on the existence of this feature or not
and for that I got a simple application which you find attached, it has a button, do something,
it's this project setup.
It uses some tooling as you learned it in the tooling section,
you need to run npm run build: dev to spin up that development server which uses webpack
dev server behind the scenes.
We will work in app.js here and our code will be output in the assets folder thereafter from which
we also import it and then in the end, we'll get this button here and our working code.
Now let's say we want to use the clipboard API and therefore temporarily, I'll add a paragraph here, some
text
you could copy and we want to make sure that when this button is pressed, copy, we put this text into
the clipboard,
so the same thing should happen as if you manually mark this and press control c, that's what we want
to replicate here.
Now to make it work, let's go to app.js
and you've got some starting code here which selects a button,
let's also select the text paragraph here with document query selector and then just the first
paragraph we find because that's the only paragraph we have
and now we can get our text here by accessing text paragraph.text content,
this is the text which is written in there.
Now we want to use the clipboard API and place that in the clipboard of the user.
Now for that, we can use navigator.clipboard,
use the right text method there and then this needs a data piece here,
here I'll just put in my text because it wants a string and thereafter, this will give us a promise.
So here, we can listen to the result, maybe console log it and see whether we get something there and
maybe also add a catch method and you could use async await instead of course and also log any error
we might be getting.
So now we have some code here which uses the navigator, the clipboard API.
If we save that and I go back here and I click copy, get undefined being logged here
but now if I go into the console here and I hit command v or control v to paste in what is in my
clipboard, you see indeed that text here was put into my clipboard,
I never manually control c'ed it,
I can prove it by marking this and hitting copy, control c and now again if I click the copy button
and I press control v here, you see again I have this text in my clipboard. So this works
and of course it works because I'm in Chrome here
and as we can tell, Chrome supports the clipboard API.
Now that's nice
but not everyone is using Chrome,
let's see if the same example works in Safari,
if you are a Windows user, you can simply try Edge. So here I am also opening up the developer tools
in the console and click copy here and now you see I'm getting an error, undefined is not an object, evaluating
navigator.clipboard write text and indeed if I tried to paste in what I copied, it's still my URL.
So in Safari, this does not work and if you tested it on Edge, it also doesn't work. Well at sometime
in the future it might work
but at the point of time I'm recording this, this is not working
and in the future, other features will not be working in one or the other browser.
So at the moment, the clipboard API is not working in Safari and not working in Edge for example.
Now right now the problem we have with that is that we got an error that is being thrown here and this
might simply crash our application, like it does here,
this is not coming from inside our catch handler because it's not the copy action that went wrong,
instead it's coming from an earlier point of time because we try to call a method on undefined because
in Safari, navigator.clipboard yields undefined and if you try to call a method on that, you get
an error
so your application crashes and that's something we of course don't want.
Now we could wrap this with try catch to catch this error but that quickly gives us code which is
a bit dirty,
so instead let's do something different,
let's use feature detection and this is very simple,
we want to use navigator.clipboard.
Now what does it yield
if this is not supported? It gives us undefined. So we can check if navigator.clipboard and you learned
that undefined will be falsy, if this gives us an object or anything else we can work with it will
be truthy and therefore we'll make it into this if block
if this is not undefined, so we'll make it into this if block
If this is available.
So now we can take the code that relies on the availability and move that into that if block and now
this code only runs in browsers where it actually is supported.
If we save that and we go back and I click copy here, in Chrome of course it still works, now let me clear that
and copy undefined instead
and now if I go to Safari and I click copy here, we don't get an error anymore.
Of course it also doesn't work,
I didn't put it into my clipboard but the app is not breaking anymore
and now we can provide some fallback code for browsers where it is not supported, simply by providing
an
else branch here
and then the simplest fallback would be that we show an error message, feature not available please
copy manually or depending on which feature we're trying to use and on what we're trying to build, we
might be able to offer an alternative route. Maybe we can go into that paragraph and preselect the content
at least, so that the user just has to press control and c, that might be a possible improvement or
we can do anything else, that really comes down to the question of what you're trying to build.
Being able to provide some fallback code here and only execute the code that uses that feature when
you need it is a great step in the right direction however and therefore feature detection and fallback
code is a great way of using certain features that might be nice to have but are not really essential
for your application, which means the rest of your application might work fine even if users can't use
this convenience button here because for now in Safari, they would simply get that alert. Checking for
feature availability and providing potential fallback code is also viable for features that might be
crucial for your application, even if you can't work around it with some fallback code and even if your
application really depends on the availability of a certain feature, you can at least use feature detection
and fallback code to show the user an error message prompting the user to switch to a different browser
for example, even that is better than just failing silently.
Also keep in mind that users of course don't visit the developer tools, so they don't even see the error
message in the console and even if they would, it might not tell them anything.
So showing at least some error message is better than doing nothing,
so even for a vital feature where you can't work around in your fallback code, having such a detection
strategy and showing an alert or an error is better than doing nothing.