3
\$\begingroup\$

I'm learning to use MVC in my JavaScript apps and I thought it might be good practice to write my own MVC implementation. I'd like to know if you see any ways I could improve it or any potential issues I could run into using it.

class Model {

  constructor() {
    this.listenerStorage = {};
  }

  trigger(event) {
    if (this.listenerStorage[event]) {
      this.listenerStorage[event].forEach((callback) => {
        callback();
      });
    }
  }

  on(event, callback) {
    this.listenerStorage[event] = this.listenerStorage[event] || [];
    this.listenerStorage[event].push(callback);
  }

  set(propObj, value) {
    if (value) { // propObj is just a string
      this[propObj] = value;
      this.trigger("change:" + propObj);
    } else { // propObj is an object with multiple values to change
      for (var prop in propObj) {
        this[prop] = propObj[prop];
        this.trigger("change:" + prop);
      }
    }

    this.trigger("all");
  }

}

class User extends Model {

  constructor(firstName, lastName, age) {
    super();
    this.firstName = firstName;
    this.lastName = lastName;
    this.age = age;
  }

}

class Controller {

  constructor(user) {
    this.user = user;
    this.initializeListeners();
  }

  initializeListeners() {
    document.getElementById("submit").addEventListener("click", (event) => {
      event.preventDefault();
      this.updateUser();
      return false;
    });
  }

  updateUser() {
    let firstNameInput = document.getElementById("firstNameInput");
    let lastNameInput = document.getElementById("lastNameInput");
    let ageInput = document.getElementById("ageInput");

    const newFirstName = firstNameInput.value;
    const newLastName = lastNameInput.value;
    const newAge = ageInput.value;

    this.user.set({
      "firstName": newFirstName,
      "lastName": newLastName,
      "age": newAge
    });
  }
}

class View {

  constructor(user) {
    this.user = user;
    this.initializeListeners();
    this.updateInputs();
    this.displayGreeting();
  }

  initializeListeners() {
    this.user.on("all", () => {
      this.displayGreeting();
    });
  }

  displayGreeting() {
    let greeting = `<p>Hello ${this.user.firstName} ${this.user.lastName}! You're ${this.user.age} years old.</p>`;
    let greetingElem = document.createElement("p");
    greetingElem.innerHTML = greeting;

    let greetingWrapper = document.getElementById("greeting");
    greetingWrapper.innerHTML = null;
    greetingWrapper.appendChild(greetingElem);
  }

  updateInputs(user) {
    document.getElementById("firstNameInput").value = this.user.firstName;
    document.getElementById("lastNameInput").value = this.user.lastName;
    document.getElementById("ageInput").value = this.user.age;
  }

}

document.addEventListener("DOMContentLoaded", () => {
  let user = new User("Joe", "Bob", 21);
  let view = new View(user);
  let controller = new Controller(user);
});
input,
label,
button,
p {
  float: left;
  clear: left;
  margin: 5px;
}
<form>
  <h3>User</h3>
  <label for="firstName">First Name:</label>
  <input type="text" id="firstNameInput" name="firstName">

  <label for="lastName">Last Name:</label>
  <input type="text" id="lastNameInput" name="lastName">

  <label for="age">Age:</label>
  <input type="text" id="ageInput" name="age">

  <button id="submit">Submit</button>
</form>

<div id="greeting">

</div>

\$\endgroup\$
  • \$\begingroup\$ " let greeting = <p>Hello ${this.user.firstName} ${this.user.lastName}! You're ${this.user.age} years old.</p>; let greetingElem = document.createElement("p"); " results in a p-tag which is nested within another p-tag. No valid HTML as far as I know. Why not just : " Hello ${this.user.firstName} ${this.user.lastName}! You're ${this.user.age} years old. " ? This is then enclosed by the created p-tag. \$\endgroup\$ – michael.zech Feb 11 '17 at 13:35
  • \$\begingroup\$ Found this about allowed paragraph content: stackoverflow.com/questions/9852312/… \$\endgroup\$ – michael.zech Feb 11 '17 at 13:39
  • \$\begingroup\$ I don't get the purpose of " const newFirstName = firstNameInput.value; ". You use it only within that function for " "firstName": newFirstName, ". \$\endgroup\$ – michael.zech Feb 11 '17 at 13:50
  • \$\begingroup\$ Why not just " "firstName": firstNameInput.value " ? \$\endgroup\$ – michael.zech Feb 11 '17 at 13:52

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.