impregnable fiend
impregnable fiend

Reputation: 289

Display changing's value in real time (Angular, JS, OOP)

So, Right now I'm practicing JS/OOP/Angular via creating some kind of light-text-browser-game :) Got stuck in the simple situation (like always). I simplify my code a bit, here it is: https://jsfiddle.net/gjgjc3fx/1/. So I've just created a 'class' Hero using factory:

angular.module('myGame', [])
  .factory('Hero', function() {
    function Hero(name, damage) {
      this.name = name;
      this.damage = damage;
    }
    Hero.prototype = {
      talk : function() {
        alert('Hi, my name is: ' + this.name + ', my current damage is: ' + this.damage);
    },
      addDamage : function(damage) {
        this.damage += damage;
        console.log(this.damage);
      }
    }

    return Hero;
  })

and then use it in controller:

  .controller('myGameCtrl', function($scope, Hero) {
    var am = new Hero('AntiMage', 70);

    $scope.currentDamage = am.damage;
    $scope.hi = function() {
      am.talk();
    }
    $scope.add50Dmg = function() {
      am.addDamage(50);
    }
   })

HTML:

<div ng-app='myGame' ng-controller='myGameCtrl'>
  <div>{{currentDamage}}</div>
  <button ng-click='add50Dmg()'>Add 50 damage</button>
  <div ng-click='hi()'>Hi</div>
</div>

The question is - what am I suppose to fix if I wanna see in the <div>{{currentDamage}}</div> changing damage in real time? I mean if I click on button it will add 50 damage and I can see change in alert's window, but the <div>{{currentDamage}}</div> stay the same (70) all the way. Any help and advices will be great.

Upvotes: 0

Views: 1605

Answers (3)

maxime1992
maxime1992

Reputation: 23793

So there's already two answers and yes, they'll be working.

But I'd like to show you how to make a reactive version of it (like you'd do with Angular2 for example).

First of all, here's a working Plunkr of your code.

EDIT : I updated the Plunkr to show you how to use component instead of controller and I created multiple instance of the game so you can see that it's well synchronized ;) !


Explanations :

Define the app

let app = angular.module('myGame', []);

Define Heroes factory

app.factory('Heroes', function() {
  // ---------------------------------------------
  // ---------------- observable -----------------
  // ---------------------------------------------
  let heroesFactoryObserver;

  let heroesFactory$ = new Rx.Observable.create((observer) => {
    heroesFactoryObserver = observer;
  })
  .share();

  // data to subscribe from controller
  let data = {};

  // ---------------------------------------------
  // ------------------- Hero --------------------
  // ---------------------------------------------
  let heroId = 0;

  let Hero = function(name, damage) {
    this.id = heroId++;
    this.name = name;
    this.damage = damage;

    this.hi = () => {
      alert('Hi, my name is: ' + this.name + ', my current damage is: ' + this.damage);
    };

    // default damage : 10
    this.addDamage = (damage = 10) => {
      this.damage += damage;
      heroesFactoryObserver.next(data);
    };
  };

  // ---------------------------------------------
  // -------------- Data to share ----------------
  // ---------------------------------------------
  data = {
    // the observable to subscribe to data change
    heroesFactory$,

    // whenever you need to force update, for example when
    // the app is loaded and you want to get data for the first time
    update: () => heroesFactoryObserver.next(data),

    // your array of heroes
    heroes: [],

    // create a new hero and add him to heroes array
    createHero: (name, damage) => data.heroes.push(new Hero(name, damage))
  };

  return data;
});

Define the controller

app.controller('myGameCtrl', function($scope, Heroes) {
  // whenever a heroe his updated
  Heroes.heroesFactory$.subscribe(h => {
    $scope.heroes = h.heroes;
  });

  // load data once by asking Heroes to trigger a change
  // so that every other component can update too
  Heroes.update();
});

It's more verbose for sure. But has it forces you to use setters (so you can trigger observer.next()), you can use that as hooks and do what you want here. Plus, instead of using angular watch and have the logic within a watch (that you'll need to duplicate for each component where you want to watch the data), you have one source by factory.


If you want to push that further, you should learn Redux and how to handle data from a single source of truth. Then you might use ng-redux.

And the best setup I've ever tried is Redux + RxJs. (and I've read that it's possible to use ngrx with AngularJs, not only Angular2).

Upvotes: 1

lahbib
lahbib

Reputation: 119

More simple

angular.module('myGame', [])

	.controller('myGameCtrl', function($scope) {
 				var vm = $scope ;
        vm.currentdamage = 20;
        
       // currentdamage = 20;
			vm.add50Dmg=function(){
      vm.currentdamage = vm.currentdamage +50;
      };
  })
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app='myGame' ng-controller='myGameCtrl'>
  <div>tst {{currentdamage}}</div>
  <button ng-click='add50Dmg()'>Add 50 damage</button>
  <div ng-click='hi()'>Hi</div>
</div>

Upvotes: 0

gaurav bhavsar
gaurav bhavsar

Reputation: 2043

your Updated fiddle

The problem is you are not updating $scope.currentDemage. For updating $scope.currentDemage you have to get the valuee from your Hero Factory.

Add getDamage function in your factory like

Hero.prototype = {
    talk : function() {
    alert('Hi, my name is: ' + this.name + ', my current damage is: ' + this.damage);
  },
  addDamage : function(damage) {
    this.damage += damage;
    console.log(this.damage);
  },

  /* getDamage function */
  getDamage : function(){
      return this.damage;
  }
}

Assign your factory instance to $scope variable in ngController like

 $scope.myService = am;

// watch getDamage() function for binding new Value.
$scope.$watch('myService.getDamage()',function(newvalue){
    $scope.currentDamage = newvalue;
})

Upvotes: 1

Related Questions