How to display player turn in AngularJS? - javascript

Beginner programmer here. In my controller constructor I have:
vm.turnCounter = 0;
vm.turn = getTurn();
function getTurn() {
if (vm.turnCounter % 2 == 0) {
return 'Player 1';
} else {
return 'Player 2';
}
}
vm is my capture variable, I'm not using $scope. I'm trying to display the current turn in my view with {{ctrl.turn}} but so far changes in vm.turnCounter has no effect on {{ctrl.turn}}, it always displays "Player 1". Am I missing some Angular databinding concepts here? Thanks.
Here's the whole controller, I omitted the super long getBoards() because it's just a long array I'll put in firebase:
(function () {
angular
.module('APP')
.controller('TicTacToeCtrl', TicTacToeCtrl);
function TicTacToeCtrl() {
var vm = this;
vm.addPiece = addPiece;
vm.boards = getBoards();
vm.turnCounter = 0; //encapsulate this
vm.turn = 'Player 1';
vm.getTurn = getTurn();
function addPiece(obj) {
if (obj.p1 || obj.p2)
obj.p1 = true;
vm.turnCounter++;
}
function getTurn() {
if (vm.turnCounter % 2 == 0) {
return 'Player 1';
} else {
return 'Player 2';
}
}
}
})();

Here is a simplified answer: http://jsfiddle.net/jd96d6kr/
In order for your view to know what is going on you are going to have to use $scope. That is the whole point of data binding in angular. Change var vm to $scope.vm
<body ng-app="APP">
<div ng-controller="TicTacToeCtrl">
<button ng-click="next()">Next</button>
turn is {{vm.turn}}
</div>
(function()
{
angular
.module('APP',[])
.controller('TicTacToeCtrl', function($scope)
{
$scope.vm = this;
$scope.vm.addPiece = $scope.addPiece;
$scope.vm.turnCounter = 0;
$scope.vm.turn = 'Player 1';
$scope.addPiece = function(obj)
{
if (obj.p1 || obj.p2)
obj.p1 = true;
$scope.vm.turnCounter++;
}
$scope.getTurn = function()
{
console.log($scope.vm.turnCounter);
return ($scope.vm.turnCounter % 2 == 0) ? 'Player 1' : 'Player 2';
}
$scope.next = function()
{
$scope.vm.turnCounter++;
$scope.vm.turn = $scope.getTurn();
}
});
})();
I'm not sure what addPiece() does, so I didn't really do much with that.

Related

Setting validation for button if atleast one check box is selected in ng-repeat

I'm facing a problem in which if I need to enable the save button if at least one check box is selected which is inside ng-repeat.
When I click for the first time it works well but dosen't work for multiple check box clicks.
Below is the working plunker:
Disabling save button
I'm using ng-change to get the selected condition..
$scope.getSelectedState = () => {
var selectedCount = new Array();
for (var i in $scope.selected) {
selectedCount.push($scope.selected[i]);
}
var allTrue = selectedCount.every(function (k) { return k });
if (allTrue) {
$scope.isSelected = false;
} else {
$scope.isSelected = true;
}
}
just change your getSelectedState . see PLUNKER DEMO
like:
$scope.getSelectedState = function() {
$scope.isSelected = true;
angular.forEach($scope.selected, function(key, val) {
if(key) {
$scope.isSelected = false;
}
});
};
and you should use ng-repeat in <tr> tag instead of <body> tag according to your plunker demo.
How about this:
$scope.getSelectedState = () => {
var selectedCount = new Array();
for (var i in $scope.selected) {
selectedCount.push($scope.selected[i]);
}
$scope.isSelected = selectedCount.indexOf(true) !== -1 ? false : true;
}
You fill the array with the checkbox values and then check if that array contains true value with indexOf
Here is my suggestion. Whenever there is any checked item, it will make variable "isAnyTrue = true".
$scope.getSelectedState = () => {
var selectedCount = new Array();
var isAnyTrue = false;
for (var i in $scope.selected) {
if ($scope.selected[i] === true){
isAnyTrue = true;
}
selectedCount.push($scope.selected[i]);
}
var allTrue = selectedCount.every(function (k) { return k });
$scope.isSelected = !isAnyTrue;
}
Here is your updated app.js:
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
$scope.name = 'World';
$scope.selected = {};
$scope.outputType = [
{
"id": 1,
"name": "Coal"
},
{
"id": 2,
"name": "Rom"
},
{
"id": 3,
"name": "Waste"
}
];
$scope.months = ["JAN", "FEB"];
$scope.values = [];
$scope.isSelected = true;
$scope.getSelectedState = (id) => {
var selectedCount = 0;
for(var key in $scope.selected){
if($scope.selected[key]){
selectedCount++;
}
}
if(selectedCount!=0){
$scope.isSelected = false;
}else{
$scope.isSelected = true;
}
}
});
Do this:
$scope.isSelected = false;
$scope.getSelectedState = () => {
var atleastOneSelected = false;
for (var i in $scope.selected) {
atleastOneSelected = atleastOneSelected || $scope.selected[i];
}
$scope.isSelected = atleastOneSelected;
}
And have following in html part:
<button type="button" ng-disabled="!isSelected" ng-click="save()">Save</button>
I'm a bit late to the question and I saw everyone already gave you a lot of great tips.
I found something different you may like, that does not involve any controller (Javascript) code.
Here is the HTML for the checkbox :
<label class="checkbox" >
<input type="checkbox" class="form-control"
ng-model="selected[item.id]" ng-init="state = -1" ng-click="state = state * -1;$parent.validFields = $parent.validFields + state;" /><i></i>
</label>
And for the button :
<button type="button" ng-disabled="validFields <= 0" ng-click="save()">Save</button>
Basically the general idea is this one : you have a "validFields" counter that starts at 0 (= no field is activated). The button is displayed if this value is above 0.
Every checkbox has a "state", that is either 1 or -1. Everytime you click on a checkbox, it adds its state to the counter, indicating whether it is ON or OFF, and switches its states. The next time you click you "cancel" the previous value that was added to the validation.
Working Plunker link here : PLUNKER DEMO
Happy coding!
call on ng- change function, (checkbox is in ng-repeat):
<input type="checkbox" name="selected" ng-model="library.isSelected" ng-change="auditCtrl.showButton()"/>
<button class="btn btn-primary" type="button" ng-click="auditCtrl.sendApproval()" ng-disabled="!auditCtrl.showSend">Send</button>
.js
auditCtrl.showButton = function()
{
var arrayCheck = [];
for(var k = 0; k < auditCtrl.libraries.length; k++)
{
if(auditCtrl.libraries[k].isSelected == true)
{
arrayCheck.push(auditCtrl.libraries[k]);
}
}
if(arrayCheck.length > 0)
{
auditCtrl.showSend = true;
}
else
{
auditCtrl.showSend = false;
}
}

Correct way to break out of if statement within for loop

What is the correct way of breaking out of a nested if statement/for loop? I have tried the following approach but the preferred approach does not work:
service.js - NOT WORKING but better because it breaks out as soon as a match is found
getSelectedService: function(serviceId) {
serviceId = parseInt(serviceId);
for(i=0;i<servicesData.length;i++) {
if(servicesData[i].id === serviceId) {
var service = servicesData[i];
return service;
}
}
}
services.js - WORKING but not good as it loops through everything even when a match is found
getSelectedService: function(serviceId) {
serviceId = parseInt(serviceId);
servicesData.forEach(function(service) {
if(service.id === serviceId) {
var selectedService = service;
}
});
return selectedService;
}
If you want to stop on the first match, you shoud use a while loop.
var keepGoing = true;
var i = 0;
var service;
while( keepGoing && i < servicesData.length ) {
if( servicesData[i].id === serviceId ) {
service = servicesData[i];
keepGoing = false;
} else {
i++;
}
}
return service;

Playing FizzBuzz in Angular

I have successfully implemented FizzBuzz in angular, and was wondering if I am doing everything according to Angular Best Practices. My questions:
1) Is there any way to set $scope.display in the factory directly instead of returning something? so instead of "return FIZZ" could I do $scope.display = "FIZZ" there?
2) do i really need separate $scope.counter and $scope.display variables?
Code:
angular.module('fizzbuzz', [])
.factory("Counter", function() {
var increment = function(number) {
if (number % 3 === 0 && number % 5 === 0) {
//any way to set $scope.display directly here?
return "FIZZBUZZ"
}
if (number % 3 === 0) {
return "FIZZ"
}
if (number % 5 === 0) {
return "BUZZ"
}
return number;
}
return {
increment: increment
}
})
.controller("FizzBuzz", function($scope, Counter) {
// is there any way to do this without a separate counter variable?
$scope.display = 0;
$scope.counter = 0;
$scope.increment = function() {
//increment the counter before going into the function, reacting to ng-click
$scope.counter++;
//call the factories function to actually display
$scope.display = Counter.increment($scope.counter);
}
})
//HTML:
<doctype! html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.19/angular.min.js"></script>
<script src="fizzbuzz.js"></script>
</head>
<body>
<div ng-app="fizzbuzz" ng-controller="FizzBuzz">
<h1 ng-click="increment()"> {{ display }} </h1>
</div>
</body>
</html>
Update:
Took Shaun's suggestion to try this but it did not display anything:
angular.module('fizzbuzz', [])
.factory("Counter", function() {
var service = {};
service.number = 0;
service.display = "";
service.increment = function() {
service.number++;
if (service.number % 3 === 0 && service.number % 5 === 0) {
//any way to set $scope.display directly here?
service.display = "FIZZBUZZ"
}
if (service.number % 3 === 0) {
service.display = "FIZZ"
}
if (service.number % 5 === 0) {
service.display = "BUZZ"
} else {
service.display = service.number;
}
}
return service;
})
.controller("FizzBuzz", function($scope, Counter) {
// can reference method and data from the service
$scope.increment = Counter.increment;
$scope.display = Counter.display;
})
angular.module('fizzbuzz', [])
.factory("Counter", function() {
var increment = function() {
service.number++;
if (service.number % 15 === 0) {
//any way to set $scope.display directly here?
service.display = "FIZZBUZZ"
}
else if (service.number % 3 === 0) {
service.display = "FIZZ"
}
else if (service.number % 5 === 0) {
service.display = "BUZZ"
}else{
service.display = service.number
}
}
var service = {
increment: increment,
number:0,
display: 'Click to start'
}
return service;
})
.controller("FizzBuzz", function($scope, Counter) {
// can reference method and data from the service
$scope.Counter = Counter;
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
Testing
<div ng-app="fizzbuzz" ng-controller="FizzBuzz">
<h1 ng-click="Counter.increment()"> {{ Counter.display }} {{ Counter.number }} </h1>
</div>
Modified to include an HTML example of usage. Also modified the FIZZ BUZZ logic based on the explanation here:
http://c2.com/cgi/wiki?FizzBuzzTest
Your questions: 1) Is there any way to set $scope.display in the factory directly instead of returning something? so instead of "return FIZZ" could I do $scope.display = "FIZZ" there?
NO, you did well !
2) do i really need separate $scope.counter and $scope.display variables?
In your controller, you don't need to put your counter variable inside your scope. It's just an increment variable.
Your increment() function can return your display number as well:
JS
.controller("FizzBuzz", function($scope, Counter) {
// is there any way to do this without a separate counter variable?
var counter = 0;
$scope.increment = function() {
counter++;
return ( Counter.increment(counter) );
}
});
HTML
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.19/angular.min.js"></script>
<script src="fizzbuzz.js"></script>
</head>
<body>
<div ng-app="fizzbuzz" ng-controller="FizzBuzz">
<h1 ng-click="increment()" ng-bind="increment();"> </h1>
</div>
</body>
</html>

AngularJS Inheritance between services

I'm quite new to the angular world and have gotten into a problem where I want to implement a Interface(isch) behavior.
I have a "core" factory which is part of my domain and it looks like the following:
(function() {
'use strict';
var domainModel = angular.module('my.model');
domainModel.factory('IVehicle', function(Timezone) {
function IVehicle(DTO) {
this.Timezone = new Timezone();
this.DTO = DTO;
this.engine = DTO.engine;
this.descriptor = this.getDescriptor();
}
IVehcile.prototype.getDescriptor = function() {
if (this.type === -1) {
return "this is a diesel vehicle";
}
else if (this.type === 0) {
return "this is a fuel vehicle";
}
else {
return "this is a environment vehicle";
}
};
IVehicle.prototype.isGenericActivity = function() {
return true;
};
return IVehicle;
});
})();
Now I have a child module which "inherits" this factory:
(function() {
"use strict";
var models = angular.module('my.model');
models.factory('Car', function(Timezone, IVehicle) {
function Car(CarDTO) {
var me = this;
IVehicle.call(me, CarDTO);
this.additionalAttribute = CarDTO.additionalAttribute
Car.prototype.hasParameters = function() {
return this.parameters !== undefined && this.parameters.length !== 0;
};
Car.prototype = Object.create(ICar.prototype);
Car.prototype.getDescriptor = function() {
if (this.type === -1) {
return "this is a diesel car";
}
else if (this.type === 0) {
return "this is a fuel car";
}
else {
return "this is a environment car";
}
};
Car.prototype.isGenericActivity = function() {
return true;
};
}
return Car;
});
})();
When I run this I get an error on this.descriptor = this.getDescriptor() in IVehicle, as Car does not know about this.getDescriptor(). The fields (this.DTO, this.engine are set in the right way)
Is this the right way to go or is there anyway I can write the IVehicle as a real interface (as a contract on what to be implemented by it's child)? If this is the correct way, how do I handle function calls within the constructor of IVehicle?

Possible to use if/else statements for $scope.$watch?

I'm playing around with Angular and trying to see if the above is possible.
<div ng-controller="Ctrl">
<input ng-model="name">
<h1>{{name}}</h1>
<h1>{{age}}</h1>
</div>
var Ctrl = function($scope) {
$scope.name = "Kevin"
$scope.age = "26"
$scope.$watch('name', function() {
if($scope.name = 'Bob') {
$scope.age = '101';
};
});
};
However, doing this just sets the value of name to "Bob" instead of "Kevin".
What am I doing wrong?
Try to use == instead of = in this line: if($scope.name = 'Bob') {
:)
here is what you are looking for try this plunker
$scope.$watch('name', function(newval,old) {
// alert(old + newval)
if (newval == 'Kevin') {
$scope.age = 99;
} else if (newval == 'Bob') {
$scope.age = 101;
}
})
Try changing the input value from Kevin to Bob and vice versa for change
Callback inside watch function should take parameter like this:
$scope.$watch('name', function(newName) {
if (newName == 'Kevin') {
$scope.age = 99;
} else if (newName == 'Bob') {
$scope.age = 101;
}
})
Here's plunker: http://plnkr.co/edit/kTOXrSfRTXE7HCUsZfh2?p=preview
Changing $scope.name between 'Bob' and 'Kevin' affects $scope.age

Categories

Resources