Coding

Adding a “Create Meetup” Form | Vue.js + Vuetify + Firebase FULL PROJECT

  • 00:00:01 welcome back to this video series about
  • 00:00:03 this view dual fired
  • 00:00:05 firebase project where we were building
  • 00:00:07 this def meetup application thus far
  • 00:00:11 were in this state we have the project
  • 00:00:13 in the state where we are able to
  • 00:00:15 actually view meetups new car cell click
  • 00:00:18 on one see the details and that's it
  • 00:00:20 we're managing this stage through UX
  • 00:00:23 already which is great but I think a
  • 00:00:25 nice next step would be if we could
  • 00:00:27 actually organize a new Meetup
  • 00:00:29 even though it won't be stored on a
  • 00:00:31 server just yet this will be a nice
  • 00:00:33 enhancement to actually really create
  • 00:00:36 our own meetup so let's implement this
  • 00:00:38 now
  • 00:00:42 I now want to make this organize meetup
  • 00:00:45 page work and for that I need a forum so
  • 00:00:49 let's start by having a look at the
  • 00:00:50 beautified documentation and actually
  • 00:00:53 see what they offer us when it comes to
  • 00:00:54 input text fields and there are text
  • 00:00:58 fields components which give us nice
  • 00:01:01 inputs for single line and multi-line
  • 00:01:04 inputs and the nice thing is this also
  • 00:01:07 has validation built in so we also get
  • 00:01:11 validation errors depending on which
  • 00:01:13 rule to configure which is really
  • 00:01:15 awesome and I will come back to that so
  • 00:01:18 I'm going to use a bunch of these text
  • 00:01:20 fields now to allow the user to create
  • 00:01:22 at least a first version of a new meetup
  • 00:01:25 we're going to enhancers later once we
  • 00:01:27 add firebase to upload files and so on
  • 00:01:30 but we can go pretty far without
  • 00:01:32 firebase already so let's go back and
  • 00:01:35 let's go to the create meetup dot u file
  • 00:01:37 or page here which is actually the page
  • 00:01:39 will load when we click on organize a
  • 00:01:41 meet up there I'll again add a V
  • 00:01:44 container to use the beautify grid and a
  • 00:01:47 V layout row now here I'll add a v-flex
  • 00:01:53 element XS twelve that's all stuff you
  • 00:01:57 already know in there I'll now add a
  • 00:01:59 heading whereas a create a new meet up
  • 00:02:03 so that we simply have a title telling
  • 00:02:06 us what we're doing maybe H four that's
  • 00:02:09 really big so create a new Meetup and I
  • 00:02:12 maybe give this a text color of primary
  • 00:02:18 – – text like that so create a new
  • 00:02:21 meetup now we load that I'll add a new
  • 00:02:24 roles and UV layout with a row and in
  • 00:02:28 there v-flex now however this reflects
  • 00:02:34 we'll get X is 12 I'm in there I'll add
  • 00:02:38 a form element I'll remove the action
  • 00:02:41 because I don't want to send a request
  • 00:02:42 to the server or anything like that
  • 00:02:45 I'll handle a submission through uks now
  • 00:02:49 in there I'll add now review layout the
  • 00:02:52 row and now here at the Flex element
  • 00:02:55 away from very small devices on bigger
  • 00:02:57 devices only half the width may be and
  • 00:02:59 therefore offsetting it – and now add a
  • 00:03:03 B text field element here that is a
  • 00:03:07 component provided by you to fire and
  • 00:03:09 the V text field component takes a name
  • 00:03:12 like normal HTML inputs you could be
  • 00:03:15 title since I want to fetch time layer
  • 00:03:17 it takes a label where we can define
  • 00:03:20 some placeholder text we will actually
  • 00:03:21 see your error sunlight liable attached
  • 00:03:24 next to it then an ID may be of title
  • 00:03:27 and I also want to add required and this
  • 00:03:31 will use the built-in validation to show
  • 00:03:33 us when this is wrong if we go back now
  • 00:03:35 you will see the input field if I click
  • 00:03:38 in that and I type there you see now
  • 00:03:40 it's valid but if I remove that we get
  • 00:03:42 an indication that this is invalid which
  • 00:03:44 is really nice would also be nice if
  • 00:03:47 that tight layer at the top would be
  • 00:03:49 kind of well aligning to our input
  • 00:03:51 fields we can achieve this by simply
  • 00:03:54 adding sm6 and the same offset here at
  • 00:03:58 the top to sort of we get the same
  • 00:04:00 styling on different devices which looks
  • 00:04:02 Li really nice in my opinion and maybe
  • 00:04:05 we change this from the primary text to
  • 00:04:08 the secondary text here or therefore
  • 00:04:13 remove it altogether since that should
  • 00:04:15 be the default anyways so now that is to
  • 00:04:17 title add it we also need to date we
  • 00:04:21 need the location we need a description
  • 00:04:24 we need an image these are all things we
  • 00:04:27 definitely need so what I'll do is I'll
  • 00:04:30 go back to the application replicate
  • 00:04:33 this add a number row now not with the
  • 00:04:36 title but with the location want to
  • 00:04:39 allow the users to simply enter that
  • 00:04:40 here so that's all the required input
  • 00:04:43 now we got two lines here really simple
  • 00:04:45 and then I want you allow user to enter
  • 00:04:49 the image now I'll see you an add an
  • 00:04:50 upload button here because we will
  • 00:04:52 actually upload an image to firebase but
  • 00:04:54 we haven't added firebase yet so for now
  • 00:04:57 people should simply enter a URL here so
  • 00:05:00 name this image URL and here M
  • 00:05:06 edge URL like that let's give this an
  • 00:05:10 idea of image – URL maybe so now we got
  • 00:05:14 this cue here we get a tiny bug that the
  • 00:05:17 line is not displayed at all times
  • 00:05:19 sometimes that happens and beautify
  • 00:05:21 really strange
  • 00:05:22 I'll next add another row where I want
  • 00:05:28 to allow the user to enter a description
  • 00:05:30 so your that will be the description add
  • 00:05:34 this here queue here also a description
  • 00:05:37 and the description should be a
  • 00:05:41 multi-line text field and we can do this
  • 00:05:43 or add this by adding multi-line here
  • 00:05:45 this will now ensure that we actually
  • 00:05:47 have multiple lines to write them we can
  • 00:05:49 even increase this if we want now when
  • 00:05:51 using multi-line if you have a look at
  • 00:05:53 the technical documentation here just
  • 00:05:56 scroll down multi line here you will see
  • 00:05:59 that you can actually also restrict how
  • 00:06:03 many lines you want to allow but all the
  • 00:06:05 way at the bottom actually there's a lot
  • 00:06:07 about validation here – so feel feel
  • 00:06:10 feel free to dive much deeper into that
  • 00:06:12 now here what you can do is if you use
  • 00:06:15 multi-line you can also use rows to
  • 00:06:19 define how many rows you want to display
  • 00:06:20 I'll stick to the default of 5 but you
  • 00:06:22 could override this that's just
  • 00:06:24 something I want to bring to your
  • 00:06:25 attention as you can see there are loads
  • 00:06:27 of properties you can use to adjust
  • 00:06:29 validation and how that all displaced
  • 00:06:31 displays definitely feel free to play
  • 00:06:34 around with that so that's the
  • 00:06:36 multi-line validation back to the image
  • 00:06:40 I believe it will all be nice if you
  • 00:06:42 would see a preview of the image maybe
  • 00:06:44 below it so here I'll not add a text
  • 00:06:47 field but actually I simply want to add
  • 00:06:49 an image property normal image element
  • 00:06:52 actually where I want to output output
  • 00:06:56 my image preview maybe or image URL this
  • 00:07:01 is a property which doesn't exist yet
  • 00:07:03 but I'll soon add properties to it will
  • 00:07:05 bind all these inputs now I can bet back
  • 00:07:08 to date and time later let's work with
  • 00:07:10 the input to get thus far and let's add
  • 00:07:14 a script section to this file now so
  • 00:07:17 that we can actually bind all these
  • 00:07:20 with two properties so export a default
  • 00:07:22 object here and there
  • 00:07:25 I now want to have my my data property
  • 00:07:30 for now and then data I will return an
  • 00:07:33 object and in that object I'll have my
  • 00:07:37 title which is an empty string initially
  • 00:07:39 I'll have my vocation which is an empty
  • 00:07:42 string initially I'll have my image URL
  • 00:07:44 which is an empty string and description
  • 00:07:47 so all the things I configure that your
  • 00:07:49 ass text fields now we can use the
  • 00:07:52 v-model on the title to bind to title
  • 00:07:54 and that's using normal view chair
  • 00:07:56 syntax here again nothing you defy
  • 00:07:58 specific except for the fact that DB
  • 00:08:00 text field component allows us to use
  • 00:08:03 the model on it but we model it than
  • 00:08:05 just normal view chairs code and I'll do
  • 00:08:08 the same here on the location and on the
  • 00:08:12 image oops image URL here and also on
  • 00:08:18 the description and this is the
  • 00:08:20 important part which allows us to fetch
  • 00:08:23 the values to user actually enters with
  • 00:08:27 that fetched there's one other thing we
  • 00:08:29 can of course do we can add another
  • 00:08:31 wheel layout towards the end of the form
  • 00:08:34 to be a row reflects XS 12 maybe and
  • 00:08:39 there I now want to have to be button
  • 00:08:42 where I actually say create meetup or
  • 00:08:46 gift is button a class of primary now if
  • 00:08:52 you have a look with the button at the
  • 00:08:53 bottom make sure to also give it s m6
  • 00:08:58 offset s and free to have it sits nicely
  • 00:09:01 in the middle here now that button
  • 00:09:04 should not be enabled at the form is
  • 00:09:06 invalid and I'll come back to checking
  • 00:09:09 this for now this is the form how it
  • 00:09:12 looks like let's see how we can enhance
  • 00:09:15 this with validation and actually using
  • 00:09:19 the values you and your to create and
  • 00:09:20 you meet up I want to start with
  • 00:09:24 validation the button should only be
  • 00:09:26 clickable of the whole form is valid
  • 00:09:27 which is currently for example it's not
  • 00:09:30 for that I'll go back to my JavaScript
  • 00:09:33 off
  • 00:09:33 here in anti computed property to this
  • 00:09:35 component the instance and I'll add a
  • 00:09:37 form is valid computed property here
  • 00:09:41 that's a third playing space there
  • 00:09:44 now here I want to return if this title
  • 00:09:47 is not equal to an empty string and this
  • 00:09:53 location is not equal to an empty string
  • 00:09:58 so basically that all of them are valid
  • 00:10:00 all these inputs and you can of course
  • 00:10:02 to find your own validation logic here
  • 00:10:04 or use another view validation package
  • 00:10:08 like V validate to cut other ways or to
  • 00:10:12 get out of ways of handling this so your
  • 00:10:14 l then also check if the image URL is
  • 00:10:16 not empty and finally of if the
  • 00:10:20 description is not empty so I'm checking
  • 00:10:23 of all these fields to have the values I
  • 00:10:25 expect them to have not being empty and
  • 00:10:27 so on we put this over multiple lines to
  • 00:10:31 make it look a bit nicer so that's my
  • 00:10:34 validation logic and now I can use
  • 00:10:36 formulas valid here in or on my button
  • 00:10:39 to bind to the disabled property and if
  • 00:10:44 that is true the button is disabled so
  • 00:10:46 if not form is valid so this computer
  • 00:10:51 property where I return this boolean
  • 00:10:53 check if that's not true then this will
  • 00:10:57 be disabled and that will be not true if
  • 00:11:00 the form is not valid which is what I
  • 00:11:02 want so now what you see is it isn't
  • 00:11:04 these disabled here as soon as I do
  • 00:11:07 enter something into all of these fields
  • 00:11:09 though it gets enabled as you can see
  • 00:11:12 image preview of course not working here
  • 00:11:14 if I were to use my own image
  • 00:11:17 like for example from Munich which is to
  • 00:11:19 say diem living in if I now choose an
  • 00:11:22 image here like this one for example get
  • 00:11:26 Dada URL then this one now if I enter
  • 00:11:31 this here you should see that we indeed
  • 00:11:33 get a nice preview well that is rather
  • 00:11:36 large here so maybe we should do
  • 00:11:38 something about the styling validation
  • 00:11:40 however it's working let's fix the image
  • 00:11:42 styling then now that we already see
  • 00:11:44 that it's an issue
  • 00:11:46 can fix that relatively easy on the
  • 00:11:48 preview image I'm using here I'll simply
  • 00:11:52 set the height to 300 we do that now you
  • 00:11:57 see it ensures that this doesn't go
  • 00:12:00 super big on small devices it's still an
  • 00:12:04 issue though so maybe we go even smaller
  • 00:12:06 than that 200 now it should also be fine
  • 00:12:10 now entirely fine on small devices I
  • 00:12:13 guess better though you can of course
  • 00:12:16 also use responsive CSS to control the
  • 00:12:18 size here I'll just try to get a fix a
  • 00:12:21 quick fix for that now that looks better
  • 00:12:24 so this would now be to set up all of
  • 00:12:27 use here now I want you make the create
  • 00:12:31 meet up button work and want to make
  • 00:12:32 sure that whatever I enter here once it
  • 00:12:34 is valid I can submit it and I do add it
  • 00:12:36 to my Buick store now for that I'll go
  • 00:12:40 back to the view X stored and add a
  • 00:12:42 mutation here create meetup seems to be
  • 00:12:47 a fitting name there I'll actually get
  • 00:12:50 the state and payload as arguments and
  • 00:12:53 in the mutation I expect to get a
  • 00:12:57 payload which already is an object
  • 00:12:59 formatted in the way I want to have it
  • 00:13:01 formatted now that's not a strict
  • 00:13:03 requirement you could also reformat the
  • 00:13:05 content you get and make sure that you
  • 00:13:07 create the object you want to save in a
  • 00:13:09 mutation so both is valid here I'll
  • 00:13:13 actually just set state and reach out to
  • 00:13:17 my loaded meters here and actually you
  • 00:13:21 simply push my new meter which again
  • 00:13:25 will be in the payload already formats
  • 00:13:26 in the way I need it
  • 00:13:27 so push it on human loaded meetups so in
  • 00:13:32 actions here of all the add a create me
  • 00:13:35 that method there I can get this object
  • 00:13:38 where I use destructuring to extract the
  • 00:13:40 commit method I'll also get my payload
  • 00:13:44 here as a second argument that will be
  • 00:13:48 the middle I actually want to create
  • 00:13:50 here I'll now create my meet up my
  • 00:13:53 meetup object and I'll set the title I
  • 00:13:56 expect to get a title property any
  • 00:13:59 payload
  • 00:13:59 I'll have to make sure that my
  • 00:14:00 application works like this but since
  • 00:14:02 you're the one configuring the store
  • 00:14:04 that something is you can control so
  • 00:14:06 you're Tyler Shelby payloads title
  • 00:14:09 location shall be payload location the
  • 00:14:14 image URL Chevy payload
  • 00:14:16 image URL and the arm description shelby
  • 00:14:22 payload description and correctly you
  • 00:14:26 would say well if I'm extracting all
  • 00:14:28 these properties which have the exact
  • 00:14:30 same names as in the object I create why
  • 00:14:33 don't I just take payload as the actual
  • 00:14:35 object and you would be right if that is
  • 00:14:38 how your application works and it
  • 00:14:39 certainly is the case for our
  • 00:14:40 application there's nothing wrong with
  • 00:14:42 doing that I'm just showing you more
  • 00:14:44 we're both way of actually mapping this
  • 00:14:47 to a new object to make sure that you
  • 00:14:50 understand that you could transform it
  • 00:14:53 here you could also build it up in
  • 00:14:55 mutations as I just said in this method
  • 00:14:57 here I chose this method I'll create
  • 00:15:00 meet up here because palos might also
  • 00:15:02 have other properties which I don't need
  • 00:15:05 or maybe other property names which I
  • 00:15:07 don't want to use here so that's why I
  • 00:15:09 choose the more verbose way it's not
  • 00:15:12 about getting done as fast as possible
  • 00:15:13 here but also just teaching you a little
  • 00:15:16 bit about UX I guess so that's the
  • 00:15:18 meetup I was using it yet though now
  • 00:15:21 here we would actually reach out to
  • 00:15:23 firebase and store it that would be the
  • 00:15:28 idea at this point here and once we did
  • 00:15:31 stories we would get back an ID firebase
  • 00:15:33 created and we will add this ID to the
  • 00:15:36 meetup and that's all stuff we will do
  • 00:15:38 once we added firebase we get a lot of
  • 00:15:41 work to do then we'll also upload the
  • 00:15:44 image here and get the storage path and
  • 00:15:46 firebase and store that all that stuff
  • 00:15:48 we have to worry about right now so I
  • 00:15:50 will simply commit here I will commit an
  • 00:15:53 X you could create meetup passed as a
  • 00:15:55 string and as a payload I will pass my
  • 00:15:58 meetup so that I can simply push that
  • 00:16:01 onto my loaded meetups array and all our
  • 00:16:04 gathers will then automatically fetch
  • 00:16:06 the updated version of that array so
  • 00:16:09 as the create meetup action I created
  • 00:16:11 now back in the create media component I
  • 00:16:14 want to fire that action whenever I
  • 00:16:16 click my button here
  • 00:16:18 however this button should actually
  • 00:16:22 submit the form remember we're still in
  • 00:16:25 a foreign object so the better way of
  • 00:16:28 handling this is to give this V button a
  • 00:16:31 type of submit and then go to the form
  • 00:16:35 and there I'll add a at submit listener
  • 00:16:38 submit this a native Dom event and we
  • 00:16:40 can listen to it it will occur once you
  • 00:16:43 click a button which is of type submit
  • 00:16:45 here I then want to prevent the default
  • 00:16:48 which would be to send an HTTP request I
  • 00:16:51 don't want to do that I don't want to
  • 00:16:53 leave my single page application here
  • 00:16:55 and then I'll call on create meetup or
  • 00:16:58 any method method name you want to use
  • 00:17:01 so with that let's go down to our object
  • 00:17:04 let's add methods here and let's add on
  • 00:17:08 create meetup as a method here now I
  • 00:17:11 don't need to get any arguments here
  • 00:17:13 because I got all the values here and an
  • 00:17:17 on create meter by now we'll simply
  • 00:17:21 dispatch my actions of this store
  • 00:17:23 dispatch and now I'll actually create my
  • 00:17:28 meetup data object choose any name you
  • 00:17:30 like where I will simply bind this title
  • 00:17:34 to this title then location to this
  • 00:17:38 location so basically create a
  • 00:17:40 JavaScript object where I store all the
  • 00:17:43 data I stored in my data property here
  • 00:17:46 so image URL this image URL and that
  • 00:17:50 will be what I pass to my store them so
  • 00:17:52 description to this description like
  • 00:17:56 that and you're ultimately dispatch my
  • 00:18:00 create meet of action and pass the
  • 00:18:03 meetup data to that action that is what
  • 00:18:06 I'll do here now again once we add a
  • 00:18:08 date and time which we haven't added yet
  • 00:18:10 this will become more complex for now
  • 00:18:13 what I want to do is I want that add a
  • 00:18:15 date here and somebody said new dates to
  • 00:18:18 get the current date so right now you
  • 00:18:22 back to the store to also handle that so
  • 00:18:25 here we'll actually then also store date
  • 00:18:27 and payload date and with that we get a
  • 00:18:31 very easy way without date and time
  • 00:18:33 Pickers without fire base without image
  • 00:18:36 upload but a very easy way of adding new
  • 00:18:38 meetups for now we will enhance this no
  • 00:18:41 worries so with that let's see if it
  • 00:18:45 works let's go back to your application
  • 00:18:46 here let me fetch this link again let's
  • 00:18:50 say Munich JavaScript meetup location
  • 00:18:55 will be at the marienplatz in Munich
  • 00:18:58 always say a great place to beat if you
  • 00:19:00 don't want to find someone because it's
  • 00:19:02 crowded with people then I'll add my
  • 00:19:05 image URL here to get the preview and
  • 00:19:08 it'll certainly be an awesome meda let
  • 00:19:12 me get to create Meetup did it work we
  • 00:19:16 don't know let's view the meetups looks
  • 00:19:18 good to me you get the Munich chalice
  • 00:19:20 copied up the date is displayed a bit
  • 00:19:22 strange here because it's in simply use
  • 00:19:24 new date and we have no way of properly
  • 00:19:26 outputting dates can now view the meetup
  • 00:19:29 here there we get an error because
  • 00:19:31 cannot read a property title of
  • 00:19:34 undefined because because we have no ID
  • 00:19:38 we try to fetch a meter by ID when we
  • 00:19:42 load the individual media but when we
  • 00:19:44 create one we don't have one now I told
  • 00:19:47 you that we will get one from firebase
  • 00:19:49 once we send our data there but that
  • 00:19:52 doesn't happen yet so for now and again
  • 00:19:55 it's only a temporary solution when we
  • 00:19:58 create a meter here I'll store an ID
  • 00:20:00 which is hard-coded into the store where
  • 00:20:03 it's not a production ready solution but
  • 00:20:05 that will do for now
  • 00:20:07 so with that let's go back to organizing
  • 00:20:09 a meet up here let's reload the page
  • 00:20:12 Munich
  • 00:20:13 Java scream was at the marine flats in
  • 00:20:16 Munich let's enter our image here and
  • 00:20:18 it'll be an awesome meetup like that
  • 00:20:23 let's create it again let's go back to
  • 00:20:25 view meetups click on it now we see it
  • 00:20:28 here now there is stuff to improve for
  • 00:20:31 example that we actually maybe navigate
  • 00:20:33 a way we clicked three
  • 00:20:34 meter button that we have date and dime
  • 00:20:37 time pickers that we use firebase the
  • 00:20:40 last thing I'll do in this video is I'll
  • 00:20:41 make sure that we navigate to the list
  • 00:20:44 of meetups once you click create but
  • 00:20:46 we'll take care about the pickers and so
  • 00:20:49 on in future videos too of course let's
  • 00:20:51 make this create media button work
  • 00:20:52 correctly or to be precise once you
  • 00:20:56 submit to me that here I want to do the
  • 00:20:58 right thing
  • 00:20:59 first of all I'll add also check if this
  • 00:21:02 form is valid if that is not true by
  • 00:21:06 adding an exclamation mark I want to
  • 00:21:08 return because I would don't want to
  • 00:21:09 submit the format the form is invalid we
  • 00:21:12 shouldn't be able to reach this code
  • 00:21:14 anyways since we disables the button but
  • 00:21:17 on the other hand the user could just go
  • 00:21:19 into the Dom and remove the disabled
  • 00:21:21 flag and then we would be able to reach
  • 00:21:23 that part so it's a nice extra check but
  • 00:21:26 more importantly once you did this patch
  • 00:21:28 I want to use the router this dollar
  • 00:21:31 sign router to used injected router
  • 00:21:33 instance to push a new route and go to
  • 00:21:36 slash meet-ups
  • 00:21:37 you could also of course navigate to the
  • 00:21:39 newly created meetup that let's go back
  • 00:21:42 to the application when final time and
  • 00:21:44 let's ask that Munich JavaScript meetup
  • 00:21:47 one more time still awesome the click
  • 00:21:51 create meetup now I'm taking there we
  • 00:21:53 see it here so the old one due to hot
  • 00:21:56 reloading in our setup here so the page
  • 00:21:58 wasn't actually reloaded and now this
  • 00:22:01 all works of course we now have the
  • 00:22:03 issue if we have two new meetups they
  • 00:22:05 share the same ID because we hard-coded
  • 00:22:08 that into our UX store will fix this but
  • 00:22:12 in the next video I want to dive into
  • 00:22:14 using date and time time pickers to make
  • 00:22:17 sure we don't use the current date and
  • 00:22:20 then I'll also take care about
  • 00:22:22 outputting the data a nicer way and
  • 00:22:25 outputting the actual place and
  • 00:22:26 description we also don't do that so
  • 00:22:29 there is still a lot of work let's move
  • 00:22:31 on and start working on these issues in
  • 00:22:33 the next video