Tic-Tac-Toe Initializing Class on Click?

Tic-Tac-Toe Initializing Class on Click?
0

#1

So im a bit stumped on this part, and honestly this is my first big try with Object Oriented JS (especially classes). Im trying to avoid global variables as MUCH as possible.

The problem seems to be around here:

function Init() {
  $("#myModal").modal("show");
  $(".modal-btn").click(function() {
    $("#myModal").modal("hide");
    $(".board").fadeIn(5000).css("display", "flex");
    console.log($(this).text() + " Chosen");
    var board = new Board("X", "Y");
  });
}

It should be instantiating a new object once the ‘modal’ is clicked, however it doesn’t seem to. (My code works if I declare a new board above document.ready for example.

Does this have something to do with nothing really having access to the click event?

I was thinking maybe I could return from Init when the modal is clicked…but that doesn’t work since Init will finish even if the modal isn’t clicked. Is there maybe a way I can return from the “click” event and then set up the new class board based on that?


#2

When you create this board object, are you expecting to be able to have access to it? The way you’ve got it now, your board is scoped to that event handler.


#3

Yeah I figured that was the issue. Is there a way on click I can return the values to maybe the class scope? Can you even return values from a click handler event?

Im trying to think of how I would get these values in a click handler event without just setting global variables.


#4

… and so the ugly side of OOP rears its ugly head.

I question whether you need to actually make a whole new board instance. Can you just write an init function that you can use to reset any single board to its original state?


#5

I guess I was just trying to use Classes in some form or another to learn them and a board class seemed the best way…I guess I could still do that with the Init though? just load some variables and instantiate the class.

that still poses the problem of the click handler however. Unless I make 2 clickhandler buttons on document.ready, one which sets the player to X and one which sets the player to O

as far as resetting, I was planning on just setting the board variables (this.board/etc…) just back to their original state (a clear object for the board itself and resetting the player variables.


#6

I understand your goal, and it’s not bad, but you’re overthinking this. The way to work with classes is to consider them “black boxes”. Imagine you’re building some sort of entertainment appliance, a physical thing like a game console or a blu-ray player. You, the engineer, know what it has to do on the inside in order to play content, handle user input, and whatever else. The user just needs to be able to plug things in and turn it on. If it’s designed well, they won’t even need any documentation - the HDMI cable goes in the HDMI port, the power cable goes in the power port. Internal functionality is exposed via controls, like a power button (it would be ridiculous to expect your user to have to turn off the machine by unplugging it).

Object oriented programming is a way to make code consumable in much the same way. The difference is that you’re probably going to be the sole consumer of your code, so you’ll need to think of yourself as the user. Think about how you would like to be able to use your board object and try to come up with methods you’d use to do so - we don’t care how they’re implemented yet, just think about what you’d like to have and worry about making it happen later. A few examples come to mind:

  • new Board() - I wouldn’t set your players in the constructor. If you want to encapsulate everything, this is where you would pass jQuery and even the global document object. Think about plugging things into your black box. This is stuff you want to do only once.
  • Board.init() - sets all internal variables to their initial state, and refreshes the UI so it’s ready for a new game
  • Board.setPlayer() - sets the player to either X or O (which sets the opponent’s piece, as well)
  • Board.makeMove() - perhaps this takes a piece (X or O) and a spot on the board, then sets the move, checks for a win, and processes accordingly

Note that each of these methods will require other methods that work internally. makeMove() would not just set the current move, but also invokes whatever internal mechanism there is for checking the win. You, the user, only needs to worry about calling that one method, though. Only consider these to be examples, though. There’s more than one way to accomplish this.

There’s nothing about classes that would necessitate this. The way you have it now would work just fine.


#7

Take a look at JavaScript Singleton design pattern. JavaScript classes has limited browser support.

JavaScript Singleton
JavaScript Design Patterns: The Singleton


#8

This is good info thanks. Im probably over-thinking it you are right (but I guess that’s expected if you are not used to OO programming). I’ve tried to use singletons as much as I can in this so far. (Caution: Wall of Text incoming)

Couple of questions about what you wrote (Which mostly makes sense):

  • On your init() function…you would probably be passing maybe a param and use that param to set this.player (and the computers Icon. But you would need to grab that param from SOMETHING (an event handler)
  • Why wouldn’t I want to set my players in the constructor? I feel like thats an initial private variable that needs to get passed around to different functions? or are you saying make the this.player declaration in my constructor but actually assign it in a different function?
  • Do people in OO Classes ever assign this.prop/value anywhere else besides the constructor? IE in a method make a this.whatever = something declaration? Does that even work? (as in does it actually set the propery for the new object when you make a new instance of the class via: let obj = new class()

So this leads to probably my biggest question: Say we have a class which represents a DOM element(s) (in this case it’s the board…which is basically the entire game for this project, so it makes sense for me to just have one class). I need event handlers (obviously) to call different functions in the class, and set initial things.

Where on earth do I attach event handlers in classes/objects? Since they are absolutely required for most javascript projects (if you want to do any interaction at all). I mean they would have to be set up in the constructor right? otherwise they won’t be set correct?

I was looking at some work code that someone had written, and this person made basically an events object which make click handlers. (In their class prototype). and then when a new instance of the class was made he did a try/catch block like so:

$.each(this.events, (key, value) => {
      try {
        this.events[key]();
      } catch (error) {
        //Fail stuff here
        return false;
      }
    });

So this sorta makes sense, he is going through each “function” in the events object (Which are basically just click handlers) and calling them.

I guess that’s like basically just setting up a click event handler for that instance of that class…but how is that any different than just setting them up in the constructor I guess is what im curious about? That’s my biggest block right now is where I should be putting them.

Just to make sure im right, from the loop above lets pretend (rewrote the code, but this is basically how it’s setup_:

 this.events[key] = makeRed: function makeButtonRed() {
      $('button[something-or-other]')
        .off('click')
        .on('click', function clickEventHandler(event) {
          const id = $(this).data('the-id'); //Grab data-the-id data value
          const thing = `div[data-thing="${id}"]`; //set a thing variable
          const color = $(this).data('color'); //Get state (active or inactive)

          methods.setColor(thing, color); //Call a method

          event.preventDefault(); // <----Not sure what this does
        });
    }

So in his case, from reading code it seems like he has events (Which grab data from this dom element and store them into variables) that call methods object (Which are usually doing any logic that needs to be done (Like in my case…setting the color and maybe making some selectors or something internall) and THEN calling a view object (Which has it’s own methods) that actually do the updating of the DOM.

I like what he’s doing and it does make sense, but that’s a huge project…and probably outside of the scope of this tic-tac-toe, but I guess im trying to insert a “taste” of that type of programming into this. And most of it makes sense. However it looks like his event handlers are really not handled anywhere and he just calls that $.each “Init” function which sets them…is that normal? Where would people normally put them.


#9

The event.preventDefault() prevents the browser from performing it’s normal behavior. Example, you have an A tag, you would use event.preventDefault() to stop the browser from opening a new window. Because, you wanted to handle the event within code.


#10

Ah useful! That makes sense. Thanks


#11

Whether or not they’re set in the constructor makes no difference.

Let’s keep two things in mind. First, the goal of encapsulating code in objects is to make that code easily consumable. A blu-ray player wouldn’t be very useful if you had to solder an AV cable to your TV instead of using an HDMI jack and cable. In that same way, you make your code less consumable if you tie it to a specific implementation. Second, we ought to keep things as simple as possible, and not rely on complicated structures to do what is conceptually simple.

I’m of the opinion that the simplest way to accomplish what you’re doing is to have your object expose its API as a few methods, like the examples I gave above, and for you to bind those to DOM events outside of your object’s definition.

var board = new Board();
$('.boardTile').click(function(e) {
    board.playerGo(e.target.attr("id"))
}

This is flexible and gives your consuming developer (most often, yourself) more control as to how your object is used. It’s also easy to communicate your intent to other developers, making your code more readable, easier to debug, and easier to think about.

As for your example code, I’m not sure why they did that, but it’s not standard and I doubt it has practical significance. It’s probably required due to some quirk of the way the rest of the code works, and I don’t suggest fixating on strange machinations to accomplish simple tasks. Never forget that programming is about communication, so your primary goal should be to write code that’s readable rather than clever.

Yes, so long as you insist on writing a constructor function. If you tie your players into your object creation without any way to change later, you run into the problem you had here where you’re having to create whole new board objects.

Yes, it works. In fact, JavaScript doesn’t really have constructors. Nor does it have private members or classes. There’s nothing special about a “constructor function” in JavaScript except that it sets the object’s prototype. But even in proper OO languages like C++, C#, or Java, getter/setter methods are a normal part of writing a class.


#12

I think I see what your saying. Make my class/methods the API (like you mentioned) and how the board gets changed, but let the outside scope of the class (so maybe in my document.ready main game loop determine how my API is “used”.

So enable to dev (me in this case) and outside the class decide When the board is created, when Players are initialized and when the “turns” (Which are going to be class methods) are handled.

All my class should do is take the data and change the board or do logic based on what I sent to it, like an API.
Does that sounds sort of like what you were trying to say?

I guess I think constructor and think "Well thats where ALL the “private” variables should go. Which I guess initializing them there isn’t a bad idea, but maybe setting them in different places is what I need to do.


#13

What you have your board object do is up to you, but whatever it does should be hidden behind some simple methods. Invoke complex operations with a clearly defined interface. That’s not “like” an API, that’s the very definition of it!


#14

I ended up revamping the whole thing, trying to take an MVC model approach.
http://codepen.io/msmith1114/pen/qmNevg (not 100% done)_

It’s honestly a bit messy right now, BUT I think it helped me grasp the general idea of how to separate items. If I had planned it out better it would be less messy…but overall I think it was at least an OO improvement on my previous.


#15

One thing about JavaScript classes, the Internet Explorer browser does not support them. So, your game does not work in IE 11. However, your game does work in IE Edge, Chrome and Firefox.


#16

Yeah unfortunately Im aware of the IE problem :frowning: but this was more for an exercise of forcing myself to learn MVC and understanding implementing it.

I mean…it’s very messy, and i’ll probably come back to it at some point, but I think it gave me at least “some” idea of it. If anyone knows of any books that go specifically into setting up this sort of structure in Javascript let me know.

Honestly the biggest difficulty was what to do in the controller…and how to handle event handlers and how they should interact.


#17

You can switch to using JavaScript Objects or IIFEs.

Here is an example I have of using an IIFE.
The “Service” is another IIFE I am using to consume a data source.

var Service = (function () {
    "use strict";

    function DoSomething(done, fail) {
        $.ajax({
            url: "https://url-datasource.com",
            beforeSend: function (xhr) {
                xhr.setRequestHeader("MyApiKey", "MyApiKey");
            },
            method: "POST",
            cache: false
        }).done(done).fail(fail);
    }

    return {
        DoSomething: DoSomething
    };
}());
//===================================
// JS Singleton Pattern IIFE
//=================================
var AppController = (function (svc) {
    "use strict";

    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    // Private
    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    function done(data) {
		"Do something";
    }
    function fail() {
        "Do something";
    }

    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    // Exposed Public
    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    function init() {
		svc.DoSomething(done, fail);
    }

    return {
        init: init
    };
}(Service));

Here are some links about IIFEs.

  1. I Love My IIFE (gregfranko.com)
  2. Immediately-Invoked Function Expression (benalman.com)
  3. 12 Simple (Yet Powerful) JavaScript Tips (javascriptissexy.com)
  4. Javascript design patterns and IIFE (codeproject.com)

#18

I am trying to complete this challenge by only using plain JS (not even any jQuery if possible). Do you think this is a positive thing or should I absolutely be using libraries and frameworks to show maturity?


#19
  1. You writing your code in plain js, without libraries.
  2. You start to notice, that you have some common code from project to project.
  3. You decide to put this code into library of some sort.
  4. After a while you acknowledge that your library needs maintenance.
  5. Sooner or later maintenance costs outweighs library usefulness.
  6. You decide to ditch your own library in favour some community library.
  7. After some painful transition to new library, you using community libraries from now on.

#20

Next big thing is to avoid any variables whatsoever (a.k.a mutable state).
You can do this project with just one mutable array as variable.