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>
Related
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;
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.
I want to show an alert if all the 5 digits in a given 5 digit number are same for example 11111, 22222, etc. Here is my fiddle http://jsfiddle.net/09k8f5s4/36/ and below is my code which is not working. Any help would be appreciated.
<div ng-app="app" ng-controller="test">
<input type="text" ng-model="value"/>
<button ng-click=check()>Check</button>
</div>
angular.module('app', [])
.controller('test', function($scope) {
$scope.check = function() {
if(/(\d)\1{2}-\1{3}-\1{4}/.test($scope.value)) {
alert("Invalid number");
}
}
});
You imply you know there are exactly 5 integers present, so I would test against mod11111.
Plain JavaScript. Assuming number is a string:
function isAllSameDigit(number){
for(var i = 0; i < number.length; i++){
if(number[0] != number[i])
return false;
}
return true;
}
This will short circuit as soon as a difference is found.
Here's a quick vanilla version (I'm not really familiar with Angular):
var num = 44444;
var num2 = 44445;
function areSame(num) {
var arr = String(num).split('');
return arr.every(function (el) { return el === arr[0]; });
}
console.log(areSame(num));
console.log(areSame(num2));
You can use the following regex ^([0-9])\1*$
angular.module('app', [])
.controller('test', function($scope) {
$scope.check = function() {
if(/^([0-9])\1*$/.test($scope.value)) {
alert("Invalid number");
}
}
});
see the jsfiddle
function check(input) {
// convert input to string
input += "";
// verify only 5 characters
if (input.length !== 5) {
throw new Error("Input is not 5 digits long.");
}
// verify it is numeric.
if (!$.isNumeric(input)) {
throw new Error("Input is not a numeric value.");
}
var allSame = true;
var firstChar = input[0];
// Loop through looking for something different
for (var i = 0; i < 5; i++) {
if (input[i] !== firstChar) {
allSame = false;
break;
}
}
return allSame;
}
Hey your regx is not correct :-
Use:- /^\D*(\d)(?:\D*|\1)*$/.test($scope.value)
angular.module('app', [])
.controller('test', function($scope) {
$scope.check = function() {
if(/^\D*(\d)(?:\D*|\1)*$/.test($scope.value)) {
alert("Invalid number");
}
}
});
Fiddle :-http://jsfiddle.net/95ydag0b/
I have following HTML
<span class="items-count">{{items | countmessage}}</span>
And following filter to show right count message
app.filters
.filter('countmessage', function () {
return function (input) {
var result = input.length + ' item';
if (input.length != 1) result += 's';
return message;
}
});
but I want use different words instead 'item(s)', so I modified the filter
app.filters
.filter('countmessage', function () {
return function (input, itemType) {
var result = input.length + ' ' + itemType;
if (input.length != 1) result += 's';
return message;
}
});
it works when I use a string like that
<span class="items-count">{{items | countmessage:'car'}}</span>
but doesn't work with a variable from the $scope, is it possible to use $scope variable
<span class="items-count">{{items | countmessage:itemtype}}</span>
Thanks
Yes, it is possible to use variable from the $scope
See this fiddle for an example:
http://jsfiddle.net/lopisan/Kx4Tq/
HTML:
<body ng-app="myApp">
<div ng-controller="MyCtrl">
<input ng-model="variable"/><br/>
Live output: {{variable | countmessage : type}}!<br/>
Output: {{1 | countmessage : type}}!
</div>
</body>
JavaScript:
var myApp = angular.module('myApp',['myApp.filters']);
function MyCtrl($scope) {
$scope.type = 'cat';
}
angular.module('myApp.filters', [])
.filter('countmessage', function () {
return function (input, itemType) {
var result = input + ' ' + itemType;
if (input > 1) result += 's';
return result;
}
});
I have an append button which appends endlessly if you click it endlessly.
Lets say i want this button to do this 10 times.
Let me tell you in fantasy code :p what i was thinking so that i can learn from my mistakes; ( i know its wrong but hey im learning)
thismany = 1;
appendbutton.onClick = "thismany = +1";
if{ thismany = <9}
appendbutton.onClick = disabled
thanks in advance
(function(){
var count = 1;
document.getElementById("the_node_id").onclick = function(){
if(count > 10){
return;
}
do_stuff();
count ++;
};
})()
UPDATE:
var count = 1;
addEvent(append, "click", function(/* someargument */){
if(count > 10){
return;
}
// if you need arguments that are passed to the function,
// you can add them to the anonymous one and pass them
// to appendFunction
appendFunction(/* someargument */);
count++;
});
This is straight javascript. You might also consider looking into a framework such as jQuery to make it easier for you.
This assumes your HTML for the button has id="appendButton" as an attribute.
var count = 0;
document.getElementById("appendButton").onClick = function(e) {
if( count >= 10 ) {
return false;
}
else {
count ++;
document.getElementById("id_of_thing_you_append_to").innerHTML += "Whatever you're appending";
}
}
Using your variable names:
var thismany = 0;
appendbutton.onclick = function() {
if (thismany++ < 10) {
// append things
}
};
Variable encapsulated:
appendbutton.onclick = function() {
if (this.count == undefined) {
this.count = 0;
}
if (this.count++ < 10) {
// append things
}
};