hi i'm carl franklin in this episode of blazor train i'll show you a few different ways to
modify your user interface based on whether or not it's being consumed on a mobile device
just like in life there's usually more than one way to do things
and it's up to you to decide which method you prefer for your application
mobile web ui is our next stop coming up right now right here on blaaaaaazor traaaaain!
so we're talking mobile web here all right so this is a blazor app where you want to
modify the experience for mobile users and you want it to be a different experience
in terms of the ui you can already see this in action in the default blazor template
if you just run it and then make the app smaller and as it gets to a certain width things change
so i've created just a single blazer server application here called mobile ui i haven't
done anything to it let me just show you what i mean here so here it is hello world
and i'm gonna make it smaller and smaller and then all of a sudden whoop what happened things
just went away well okay so this nav bar over here went to the top and we also got this little button
right here that allows us to drop down the nav bar now this nav bar is actually just a bootstrap
nav bar in fact if you go to getbootstrap.com or just search for bootstrap navbar you can see
that the documentation shows you how it works and it even has a nice little demo of it right here
and even the demo uh does what our blazor template does let me see if i can make this smaller
there it goes so it's got a button here however you might notice that the sample code
is a bit different here like there's a data toggle collapse a data target
there's a bit more stuff here than is in the nav bar that we have in our blazor template so we're
going to do this three ways we're going to control the mobile ui in three different ways one with css
one with javascript and one with blazor so the css solution is based on the size of this display the
width right the minimum width you can see this happening if you go to shared nav menu razor css
you can see right here there's a media query so what's going on here
is that if our browser is 641 pixels wide or wider then in the navbar toggler class we're going to
hide it set display equals none this is css right in the collapse class we're going to display
so i know that you can't really get the whole thing from this but this is the general idea let
me simplify it for you let's go back to fetch data and i'll put a little div right down at the bottom
here all right so this div is using the class non-mobile and it says there are at forecasts
length forecasts right so now we have to get a class called non-mobile so what i'll do just to
localize it to fetch data is we'll add a fetch data.razor.css and just put that class in there
non-mobile is going to default to being hidden display none but
when we're 641 pixels or greater we're going to show it display block
all right so this is basically a very simple class that when it's 641 pixels or wider
we're going to display it and when we're less than 641 pixels wide we won't now again going
back to our div class equals non-mobile this should only show up when we're not compressed
all right here's our fetch data there you can see there are five forecasts and if i
do this boom goes away now here's another thing that you can do you can actually add this class
to any element that you don't want to show so this class equals non-mobile let's say we don't want to
show the uh temperature in celsius when we're mobile or when we're at a lower width all right
so i put the class on this one and on this one all we're doing is saying hey you know if we're
so wide show it but if we're not don't show it all right so there it is we have our temp celsius and
boom just goes away so this is a nice css based solution but it does have its limitations what
if you want to do some code that inspects whether the screen is a certain width
or not a certain size and then do things or show things based on that using code you know using
this kind of stuff you know if we're mobile then show something otherwise show something else
maybe you want to do that so for that we can use javascript
so i'm going to go into my underscore host cshtml right there and add a little bit of script
so we've got this script i've got a variable called blazer page which is going to be a blazor
page reference that we pass in with javascript interrupt the method is window.register for resize
events and when that happens we're going to save off that blazor page and set a reference to it
and now i have an event listener for the resize on the window so that means anytime the browser
gets resized this is going to happen so i've got this raise event internal function that i call on
a timeout just after one millisecond just to get me out of the call stack right it's just a little
stupid javascript trick i learned essentially we're going to call that with the component and
the event name and the x and the y and it's going to call invoke method async on window resized
that's our event name so in c sharp i have to have a js invokable method called on window resized
that accepts a width and a height integer i have to call that immediately after calling
register for resize events because i need to know what that width and height are
you know initially so now let's rewrite fetch data razor to handle this all right so i've got um an
ijs runtime there for javascript runtime and let's go down here and you can see i've still got this
css thing in there but i've also got all this right here window width and window height which
are integers and on after render async i have to do this here otherwise the javascript system
isn't initialized it doesn't work you can't use uninitialized async can't call javascript in there
so you have to wait until it renders the first time and net object reference dot create this
is my page a reference to my page which the javascript is going to use to call back
on window resized and all i'm doing here is setting my window width and height
and calling state has changed so now keeping with our 631 pixels
if my window width is greater than 631 i'm going to show this div
all right so it's similar but now i'm using javascript so i can start
inspecting variables that come back from javascript
all right here's our window width let me uh bump this pump this up a little bit
and when we get down to a certain width boom there it is
i guess it would be better if you could see it huh there so not at all being shown when
we're below 631 and when we're above that it shows it so you got to think about the pros
and cons of css versus javascript we're using both of these here but these are
only based on the width of the screen how can you tell if there's an actual mobile device
that's connected well that's different so let's go back to our underscore host and change that
so check this out this underscore host cshtml happens on every refresh
so every time the page because it is a spa so every time the page is reloaded
and i don't mean go from page to page i mean you press refresh right then this is going to happen
and we're looking at the user agent from the request headers user agent
and then we're looking to see if that user agent string contains any of these types that indicate
mobile platforms now this mobile right there is going to cover a host of sins in android as well
but there are also a couple other ones that you might want to look for as well
so all we're doing here is getting this is mobile boolean true or false based on the user agent now
how do we get that into our application well this is a really cool trick we're going to
deck out the app object the app raiser page and we're going to add a parameter called is mobile
and then we can hook the navigation in there in the app and based on whether it's mobile or
not we can reroute to different pages so let's start by adding app.razor.cs
so this is a code behind for our app public partial class app we're implementing eye
disposable which is cool here's our is mobile parameter we're injecting the navigation manager
now we've got uninitialized our navigation manager location change we're going to
handle that event with this delegate on location changed and here's our on location change delegate
and all we're doing there is calling nav check so i'm getting the nav path in other
words where are we navigating to from the navigation manager uri local path to lower
and now i'm saying if is mobile which we know is true or false and the nav path does not start with
forward slash mobile then we're going to create a new path prepending it with mobile and by the way
um we're going to take off the uh forward slash from whatever the current nav path is so you can
do whatever you want to here you can say hey you know what if it's index go to the mobile
index but if it's these pages like counter and fetch data those are fine just let the css work
its magic but if i want to build an a completely different page that's mobile for mobile devices
different ui right different strategy a lot of things not there a lot of things look different
then i can do that this way and i can cherry pick which ones i want to show if we're mobile but i'm
using a sort of convention over configuration approach right here so what we're going to do
is we're going to create a mobile page a mobile counter page and a mobile fetch data page and so
if we're mobile on a mobile device and we navigate to those it'll reroute us to the correct mobile
version so let's make those pages now actually i'm going to create another folder called mobile pages
in there i'm going to create mobile index i'm going to create mobile counter
and mobile fetch data
so let's start with fetch data here's our mobile index and mobile counter so you can see all i've
done here is besides the page directive being you know mobile counter whatever i've just set
you know something that we can identify this as definitely the mobile version of this page
in this case of the counter it still has the code to increment the counter and the button and
all that stuff that's exactly the same in the case of index this is just going to be called
mobile because remember this is the path to the regular index so this is just going to be mobile
and as for fetch data this will be called mobile fetch data all right so again
host determines whether we're on a mobile device or not
creates the app with the parameter is mobile okay the app gets a nav check uninitialized
and anytime that there's a navigation checks to see if we are mobile and the path that we're
asking for is not mobile and if it isn't then we're rerouting to a new path that is mobile
now how do we test this well i'm using chrome my web browser is google chrome
right here google chrome has a nice feature where you can sort of emulate a mobile device
so i'm going to press f12 and then shift control m and there's our mobile but why isn't it saying
you know why doesn't it tell us that we're on a mobile device well because remember
we have to refresh in order to reload that cs html file and now it's mobile
you can see mobile index and it's slash mobile up there if i go to counter
there's our mobile counter page and that works
just like you'd expect you and our mobile fetch data page
and by the way you can see our mobile fetch data page
we took the celsius completely out of that whether we are you know this wide or this wide
right just to show you that you can do something unique now what happens if you want to navigate
in your code directly to one of these pages but not to the mobile page well that's what you do
you write all your code even in your mobile applications to navigate to the non-mobile pages
and then this nav check will do the work of making sure that you get to the right page
so let's go to mobile index and let's just add a button here
so the button is to fetch data and when we go to fetch data it's navigate to
fetch data the non-mobile version right well let's see what happens when we do that now this is from
the mobile index right all right f12 shift control m reload now i got my fetch data button click that
and look at that it's gone to the mobile fetch data page automagically you don't have to do
anything all right so i'm not telling you which one you should use in your project
obviously there's three different approaches you can use a combination of all of them you know
start with css if you think that's going to be easiest for you just showing and hiding elements
based on the width or you know completely changing the way things look with css based on the width
but if you want to know if you're on a mobile device you can use this method and if you want
to use javascript to determine the actual width so you can examine it in code then you can do that as
well i hope this has been an informative episode of blazor train back to you in the studio carl
you know css purists will tell you that using media queries is the only way to go
that's the accepted modern way to do responsive ui
but what if you're months into a project and the boss says oh yeah
you got to make this app work on an iphone well now you have options move up to business class hey
thanks for riding the rails with me today this is where i jump off i'll see you next time
you