Let's assume we made it past this if check
so we do have a valid input.
Now, of course, I wanna store that data somewhere,
that entered player name,
and I also wanted to show it here
on the page, on the screen
but, of course, I wanna update the correct player here
because we've got two players,
and, of course, I wanna update the one
for which we clicked on edit.
Now, we're using one and the same overlay
and one and the same form submission function
at the moment.
How can we now differentiate between the two players
and update different parts of the screen?
With help of another new feature,
which I'll show you in this section,
which can be useful in scenarios like this.
You can add extra data to your HTML elements,
which are not visible on the page here
but which you can use and read
in your JavaScript code
to then add extra information to certain elements.
Sounds very abstract?
Well, let me show you what I mean.
In your HTML code,
we've got these two buttons for the different players.
Now, they do already have different IDs
and we could try to parse the ID of the player-1 or 2
from these IDs,
but we can also add a brand new attribute,
which you can add to any HTML element.
And that's the data attribute.
Now, the data attribute is a special attribute.
It's not an attribute which you add just like this.
Instead, it's always data-
and then any identifier of your choice.
And all the other attributes,
which we added thus far,
and all the other attributes,
which we typically use are just one-word attributes.
This consists of multiple words separated by dashes.
Now, the first word is always data
but then thereafter, as mentioned,
you have any identifiers of your choice.
For example, playerid.
Now, then you assign a value, in this case, one
and for the other button,
I'll use two, like this.
And you can read that data here
with help of that key that you added after data-
in your JavaScript code.
Now, I'll reformat this here
to make this a bit more readable
but we still have data-playerid on the two buttons.
Now, we can use this in our JavaScript code.
When the modal is opened with help of openPlayerConfig,
then we know that this button was clicked,
either the first or the second edit button.
Now, we can get access to the click button
with help of that event object,
as we saw before for the form.
And as we learned before in the other course sections.
Event.target gives us access
to the element for which the event occurred,
in this case, it gives us access to the button
that was clicked.
So here we have the clickedButton.
However, I'm not interested in the clickedButton.
Instead, I'm interested in the data which I added
to the button
because that will be different depending
on which button was clicked.
Here in config.js on event.target,
so on the button that was clicked,
we have a dataset property.
And this property exists on every HTML element
with which you interact in your JavaScript code.
This is a object that will be populated
with all the data attributes you added to your elements.
And by the way, you can have multiple data- attributes
on one and the same element.
Now, the data- part will be ignored
but the part thereafter will be added
as a property to this object, to this dataset object.
So here, since I added playerid on both buttons,
we have a playerid property written like this.
And you should use exactly the same notation
as you used in your HTML code.
If you have a dash here,
if it's, for example, player-id for you,
you could make that work
but in that case, you have to access it like this,
which is a different way of accessing properties
on JavaScript objects, totally independent
on whatever it's a dataset object or another object,
which you can use if your property name uses a dash.
Because a dash is not allowed with the dot notation,
that's why you have this alternative square bracket notation
for such property names.
But here, I actually have playerid without a dash
in playerid, and hence, I can just use the dot notation.
And then I have the selectedPlayerId here,
which is now a more fitting name for this constant.
And that will now differ depending
on which edit button was clicked.
Now, why is that useful?
Well, we can now store this information
to know which player we're currently editing.
And for this, in app.js,
which is my main initialization file,
I'll add a brand new variable at the very top,
and now it's a variable created with let,
not a constant
because I plan on changing the value stored in there,
which I'll name editedPlayer.
And this initially let's say is zero
but now I wanna set it to the ID that I set here.
So either one or two.
And therefore in config.js,
now that selectedPlayerId was extracted here,
I can set my editedPlayer, so this variable,
which we just added in app.js
equal to selectedPlayerId.
Alternatively, we skip the step
of creating that extra constant
and we directly set editedPlayer like this.
Here we don't have let or constant in front of this
because I don't wanna create a new variable or constant
of this name.
Instead, I'm just overriding the variable
that was defined here in app.js.
And this will now either hold a value of one or two.
Very important though,
it will actually be a string,
so it will be of type string
even though this is a number
but whatever you store in such a data attribute
will be treated as a string value type,
and I rather would work with a number here,
so I'll add a plus in front of this
so that this is converted to a number
because plus one as a string
will yield one as a number.
So it's simply the value type that will be changed.
And with that, we're storing the ID of the player,
which we are editing in this editedPlayer variable.
And we'll soon use this information
because now in savePlayerConfig,
I wanna update that player with that ID,
both in my code, and also very important, on the screen.
I wanna change this player name here.
Now, how can we update what's shown on the screen here?
How can we update these h3 elements here?
Well, there will be different ways of achieving this
but ultimately, we could get access to this ordered list,
and then just get these list items as array elements.
And then either update the first
or the second array element based
on which player was selected.
Or we assign IDs here to the article
and we use IDs like player-1-data
and player-2-data, and that's what I'll do here.
So I'll add IDs here to these articles
with player-2-data and player-1-data.
And then I can use these IDs
to select the appropriate player
and well, update the data.
So in config.js, after this validation,
so now that we know that we do have a valid player name,
I will actually get my updatedPlayerDataElement
and I get this with help of document.getElementById,
and now I'll do something interesting.
I'll add a string here
and the ID, of course, is either player-1-data
or player-2-data.
And now I'll construct this string dynamically based
on the editedPlayer that's stored in this variable,
which is either one or two.
So here I'll start with player-
because either way, the ID starts with player-.
But then I add one or two,
so I concatenate with the plus symbol.
We can use this on strings as well
to combine multiple values into a longer string,
and I'll add editedPlayer,
which is one or two as a number
but it will be converted
to a string automatically by JavaScript.
And then thereafter, I add -data
because the full ID should be something like player-1-data
or player-2-data.
And now with that code here,
we are constructing this ID dynamically
and hence, we're selecting
the correct player article dynamically based
on the edited player ID
that we set here in openPlayerConfig.
And therefore, now we got hold of the correct player element
and I know that I wanna update the h3 element in there,
which is the second child element,
and hence, to again practice DOM traversal,
we can use the updatedPlayerDataElement
and then the children property,
which gives us an array
of all the child elements we have in there.
And we can get access to the second element with on
since you learned that arrays start at index zero,
hence one is the second element, not the first one.
And the second child element in these articles
is this h3 element, which we wanna update.
So here in config.js,
I'll now set the value of that element,
the textContent equal to,
and then that should be the name that was entered,
so the enteredPlayername, like that.
And with that, we're updating the enteredPlayername
on the screen.
Now, if I reload this and I set Max for player two,
if I click Confirm, and cancel this,
this was set to Max.
And if I set player one to Manu and click Confirm,
and close this, this was set to Manu.
Now, of course, it should close automatically,
and we'll do this in a second,
but before we do that,
I also wanna store the enteredPlayername internally
in my JavaScript code, not just in the h3 element here
because we'll also need the player name later
once we've got a winner.
And I then don't wanna reach out to this h3 element
and get my value from there,
even though we could do that as well.
But it's cleaner and better if we store the player names
in our JavaScript code as well
so that we have essential data like that right in our code,
and we don't need to get it from the HTML page later.
Therefore, in app.js,
I'll add more helper variables or constants.
And here, I'll add a constant called players,
which actually should be an array
because we'll have two players.
We could also create two separate variables or constants
but grouping the data together
into an array makes sense here.
And I use an array instead of a standard object
because I have multiple items of the same type
with different detail data.
To be precise, I wanna have two objects here in this array
and we can write it like this
across multiple lines to improve readability,
separating the items with commas.
And each object will have a name property,
which is the player name,
and a symbol property,
which is the symbol associated with that player.
Now, the symbol will be unchangeable.
It's X for player one
and for player two, it's this O.
But, of course, the name has to be set.
Initially it's empty and we have to ensure
that it is set before the game starts.
Now we have this players array
and now I wanna update the players
whenever a name was entered for them.
We can update the data in this constant,
even though it is a constant
because I'll not assign a brand new overall array
to players, instead I'll just edit existing elements
inside of that array.
And that is possible,
though I'll take a closer look at why that is possible
a little bit later in the course
once we learned even more about JavaScript.
So now here back in config.js,
besides updating what we see on the screen,
I'll reach out to this players constant,
and now I wanna access one of the two elements.
Since it's an array, we use the square bracket notation
for that, and we can get hold of the first element
by using zero, and the second element by using one.
Now, to get access here,
we could check if the editedPlayer, which is one or two,
is equal to one, and if that's the case,
we access players zero, so the first element,
which is our first player,
and else we access players one,
and we then set different values for the names in there.
So then we set name equal to enteredPlayername
for the second element here.
Otherwise, we do that for the first element, like this.
This is how we could write this
and check which player we are currently editing.
This would work but if we think about this code,
we can actually come up with a shorter,
more concise solution.
Instead of writing this if-else check,
which might be a nice practice,
we can also reach out to players
and just calculate this index dynamically.
Keep in mind that editedPlayer stores one or two as a number
because I change it to a number here.
The index which we need also is a number.
The only difference is that this number for the index
should start at zero whereas editedPlayer is one or two.
But since the player with ID one has index zero,
and the player with ID two has index one,
we can just deduct one from the editedPlayer value
and then access the correct index
because for player one, this yields zero,
and therefore, we access the first player in there.
For player two, this yields one,
and hence, we access the second player here in this array.
And therefore, we can then just set the name
of that player that we accessed here equal
to enteredPlayername and that's a more concise way
than writing this if-else statement,
which you, of course, could do as well though.
Okay, so now we got that
and now we're also storing that player data internally.
We won't see that if I try that here
but we also don't get any error here.
So it probably works.
We'll see whether it works later
once we need the player name.
Now, before we work on the actual game logic
and on starting that new game,
let's make sure we close that modal automatically though
when we click confirm.
And that's fairly easy to achieve.
All we've gotta do for that
is at the end here of savePlayerConfig,
if we did update our player data,
we just have to call closePlayerConfig manually.
So here we do add parentheses.
We are executing this function here manually now.
Before we just pointed at it here in app.js
for our listeners, for our click listeners
on the cancel button or the backdrop,
now I wanna explicitly execute this function myself
if we are done submitting that form.
And that's a great example
of when to call a function yourself
versus when to hand it off to the browser.
If you wanna listen to events,
you wanna let the browser execute a function.
Here we wanna do it ourselves though
because we are done with some other operation,
which itself was triggered upon an event though,
the form submission,
and therefore, this is how the circle closes so to say.
And therefore, now we close the modal ourselves
once we're done with validating and storing
that entered data.
And hence now if I enter Max here and click Confirm,
this closes, we see the value here.
And I can enter Manu here,
and see this here.
The last tweak I wanna perform
is now that if I did enter Manu here,
and I confirmed, that value stayed in there.
If I enter Max here now for player one,
and I then start editing player one,
this starts with Max.
The reason for that is we only reset that form
if we click Cancel.
Not if we click Confirm.
By the way, also not if you click the backdrop.
There we would also persist what was entered here.
And therefore, as a last step,
I will indeed also clear the entered value manually
when we close that modal with closePlayerConfig
by getting access to that input element
and manually setting what's entered in there
to an empty string.
For this in closePlayerConfig,
I wanna reach out to my formElement,
so to the overall form,
which we have in there,
and there I wanna get access to that first input,
which we find in there.
Now, there are different ways of getting hold of that.
And actually, using the ID might be best
with document.getElementById
but I wanna practice more DOM traversal,
so I will use the formElement as a starting point,
then dive into the firstElementChild
and then into the lastElementChild,
which will also yield me that input.
So therefore here, I use
formElement.firstElementChild.lastElementChild
and that is then that input element
where I will set the value property,
not nodeValue but value,
which exists on input elements
when you use them in JavaScript
and set this to an empty string
to reset what's entered in there.
Again, this is not necessarily the best way of doing it
because if I start adding more elements,
for example, after this input,
if I have a paragraph there,
then this way of selecting the input
wouldn't be correct anymore
because lastElementChild now would be the paragraph.
But I'm not adding a paragraph here,
and therefore, this is now simply again
another nice practice
of how you can dig into a DOM structure in JavaScript.
You might, of course,
use the playername for directly selecting the input
in a more secure and shorter way.
That would probably be the better way
but again, I wanted to practice this here again,
so that's how we'll do it here.
And with that, we're manually setting the value
that's entered in this input field to an empty string
so that with that,
if I set this to Max and confirm,
this is still reset if I then open the other field,
and if I, for example, enter something
and click on the backdrop, we also clear this.
So that's now better than before.
And with that, we spent a lot of time on the configuration
but we had a lot of key concepts here,
a couple of new concepts as well.
Now it is time to move on to the game though
to make this Start New Game button work,
and only show that game field
if we did start a new game,
and then it's, of course,
time to register these clicks here,
update the game board and check for a winner.