Here i add a delay in javascript forloop using $timeout. Unexpectedly i got an error saying
ReferenceError $timeout is not defined. i am new to angularjs please help me.
PLNKR
function CompLibrary() {
return {
init: init
}
function init(dependencies, controller) {
dependencies.push(controller);
angularApp.controller('MainCtrl', dependencies);
}
}
var compX = CompLibrary();
compX.init(deps, _controller);
function _controller() {
var ViewModel = this;
ViewModel.search = "Name";
ViewModel.quantity = 1;
for(var i = 0; i < 4; i++) {
(function(i){
$timeout(function() {
ViewModel.quantity++;
}, i * 2000);
})(i); // Pass in i here
}
}
You have to inject the $timeout into the controller function.
function _controller($timeout) { ... }
Please see updated Plunkr
var deps = [];
var angularApp = angular.module('plunker',[]);
function CompLibrary() {
return {
init: init
}
function init(dependencies, controller) {
dependencies.push('$timeout');
dependencies.push(controller);
angularApp.controller('MainCtrl', dependencies);
}
}
var compX = CompLibrary();
compX.init(deps, _controller);
function _controller($timeout) {
var ViewModel = this;
ViewModel.search = "Name";
ViewModel.quantity = 1;
for(var i = 0; i < 4; i++) {
(function(i){
$timeout(function() {
ViewModel.quantity++;
}, i * 2000);
})(i); // Pass in i here
}
}
By injecting $timeout in the controller function we can solve this problem.
Related
I am working on a game using HTML and Javascript. And I need a function to be called every 2 seconds. I tried using setInterval but the function is not being called. And the browser console does not show any errors.
function Apples() {
this.Apples = [];
this.indexCount = 0;
this.CurrentTime;
this.createApples = function() {
this.Apples[this.indexCount] = new Apple();
this.indexCount++;
}
this.updateApples = function() {
for (var i = 0; i < this.indexCount; i++) {
this.Apples[i].positionY += 1;
this.Apples[i].drawApple();
}
}
}
var apples = new Apples;
setInterval(apples.createApples, 200);
It does not work because of the context of this and your code is 200 milliseconds, not 2 seconds.
function Apple () {
return {
positionY: 0,
drawApple: function () {}
}
}
function Apples() {
this.Apples = [];
this.indexCount = 0;
this.CurrentTime;
this.createApples = function() {
this.Apples[this.indexCount] = new Apple();
this.indexCount++;
console.log("new index", this.indexCount);
}
this.updateApples = function() {
for (var i = 0; i < this.indexCount; i++) {
this.Apples[i].positionY += 1;
this.Apples[i].drawApple();
}
}
}
var apples = new Apples;
// use bind
// setInterval(apples.createApples.bind(apples), 2000);
// or use function
setInterval(() => apples.createApples(), 2000);
//setInterval(function () { apples.createApples(); }, 2000);
How can a method be called dynamically from a class in ES6?
In ES5 and lower I can do this with the following. JSFiddle example
var App = function() {
var that = this;
this.init = function() {
var elements = document.getElementsByClassName('call-method');
for(var i = 0; i < elements.length; i++) {
elements[i].addEventListener('click', function() {
that['method' + this.dataset.method](this);
});
}
};
this.methodOne = function(element) {
console.log(element.innerText);
};
this.methodTwo = function(element) {
console.log(element.innerText);
};
};
(function() {
var app = new App();
app.init();
}());
When I try to do the same in ES6 I get an error Uncaught TypeError: not a function. Is this possible in ES6 or am I doing something wrong here? JSFiddle example
'use strict';
class App {
constructor() {
var elements = document.getElementsByClassName('call-method');
for(var i = 0; i < elements.length; i++) {
elements[i].addEventListener('click', function() {
this.constructor['method' + this.dataset.method](this); // Uncaught TypeError: not a function
App['method' + this.dataset.method](this); // Uncaught TypeError: not a function
});
}
}
methodOne(element) {
console.log(element.innerText);
}
methodTwo(element) {
console.log(element.innerText);
}
}
(function() {
new App();
}());
I think you're misunderstanding how ES6 classes work. Your first strategy is not going to work, because this.constructor is a method, not a reference to any constructor class. The second won't work, because that would only reference a static method.
Instead:
constructor() {
var elements = document.getElementsByClassName('call-method');
for(var i = 0; i < elements.length; i++) {
elements[i].addEventListener('click', (e) => {
this['method' + e.target.dataset.method](e);
});
}
}
Also arrow functions are going to be a better way to bind the event.
Edit: Updated your fiddle to show it in action - http://jsfiddle.net/dqk8n3xk/3/
You can do the following:
'use strict';
class App {
constructor() {
var that = this;
var elements = document.getElementsByClassName('call-method');
for(var i = 0; i < elements.length; i++) {
elements[i].addEventListener('click', function() {
that['method' + this.dataset.method](this);
});
}
}
methodOne(element) {
console.log(element.innerText);
}
methodTwo(element) {
console.log(element.innerText);
}
}
(function() {
new App();
}());
as shown in this jsfiddle
I am trying to clean up a controller that has too many lines of code in it. In the controller below where you find a function called getProductDetails, I would like to move the filter to a factory or a service, but I am not sure how to do it.
'use strict';
(function () {
var userQuoteBuild = angular.module('priceApp');
userQuoteBuild.controller('quoteBuilderController', function ($scope, $http) {
// loads of controller logic here...
$scope.getProductDetails = function (item) {
$scope.listOfProductVariants = item.default_variant_attributes;
// TODO: put this in its own factory?
$scope.selectedProductAttributes = $scope.listOfAttributes.filter(function (item) {
var validated = false, i, length = $scope.listOfProductVariants.length;
for (i = 0; i < length; i++) {
if (item.name === $scope.listOfProductVariants[i]){
validated = true;
}
}
return validated;
});
};
});
(function () {
'use strict';
angular
.module('priceApp')
.factory('filterService', filterService);
function filterService() {
var service = {
getValidated: getValidated
}
return service;
function getValidated(list, variants) {
return list.filter(function (item) {
var validated = false, i, length = variants.length;
for (i = 0; i < length; i++) {
if (item.name === variants[i]) {
validated = true;
}
}
return validated;
});
}
}
})();
Simply inject this filterService to your controller and then use it as in example here:
$scope.selectedProductAttributes = filterService
.getValidated($scope.listOfAttributes,
$scope.listOfProductVariants)
I followed John Papa's AngularJS Style Guide. Make sure to choose a better name than filterService. : )
Check this:
userQuoteBuild.factory('myService', function() {
var service = {
getProductDetails: function(item) {
// your logic
return value;
}
}
return service;
});
In the following code snippet, 'this.x()' can only be called in case 2 (see main()).
Also Bar unequals this in case 1, but is equal for case 2.
function Class_Bar() {
this.panel = null;
this.init = function () {
// do some stuff
this.panel = 20;
}
this.apply = function () {
alert(Bar == this);
Bar.x();
this.x();
}
this.x = function() {
alert("Some friendly message");
alert(Bar.panel);
}
}
var Bar = new Class_Bar();
function Class_Factory() {
this.factories = new Array();
this.add = function (init, apply) {
this.factories.push({"init":init, "apply":apply});
}
this.init = function () {
for (var i = 0; i < this.factories.length; ++i) {
this.factories[i]["init"]();
}
}
this.apply = function () {
for (var i = 0; i < this.factories.length; ++i) {
this.factories[i]["apply"]();
}
}
}
var Factory = new Class_Factory();
function main() {
// Case 1
Factory.add(Bar.init, Bar.apply);
Factory.init();
Factory.apply();
// Case 2
Bar.init();
Bar.apply();
}
main();
http://pastebin.com/fpjPNphx
Any ideas how to "fix" / workaround this behaviour?
I found a possible solution, but it seems to be a "bad" hack.: Javascript: How to access object member from event callback function
By passing Bar.init, you're really only passing the function but not the information that it belongs to Bar (i.e. what the this value should be). What you can do is binding that information:
Factory.add(Bar.init.bind(Bar), Bar.apply.bind(Bar));
I just started using oop in javascript and I ran across some problems trying to acces a method from inside another method.
here's the code I had:
var Game = {
initialize: function () {
if (canvas.isSupported()) {
sprites[0] = new Player();
this.update();
}
},
update: function() {
for (var i = 0; i < sprites.length; i++) {
sprites[i].update();
}
this.draw();
},
draw: function() {
this.clear();
for (var i = 0; i < sprites.length; i++) {
sprites[i].draw();
}
setTimeout(this.update, 10);
},
clear: function() {
canvas.context.clearRect(0, 0, canvas.element.width, canvas.element.height);
}
}
but calling the Game.update() gives an error that the draw method isn't defined.
I couldn't find a real solution for this.
eventually I found this How to call a method inside a javascript object
where the answer seems to be that I need to safe the this reference like:
var _this = this;
but I couldn't get that to work in literal notation, so I changed the code to object constructor (I guess that's how it's called) and added the variable.
I then changed
this.draw();
to
_this.draw();
and it worked.
though the
this.clear();
and the this.update() are still the same, they never seemed to give errors in the first place.
Can anyone explain why this is? and maybe point me to a better solution?
thanks in advance.
update
Here's what it should be:
var Game = function () {
var _this = this;
this.initialize = function () {
if (canvas.isSupported()) {
sprites[0] = new Player();
this.update();
}
}
this.update = function () {
for (var i = 0; i < sprites.length; i++) {
sprites[i].update();
}
this.draw();
}
this.draw = function () {
this.clear();
for (var i = 0; i < sprites.length; i++) {
sprites[i].draw();
}
setTimeout(function () { _this.update(); }, 10);
}
this.clear = function () {
canvas.context.clearRect(0, 0, canvas.element.width, canvas.element.height);
}
}
When you do this:
setTimeout(this.update, 10);
that does correctly pass the reference to your "update" function to the system, but when the browser actually calls the function later, it will have no idea what this is supposed to be. What you can do instead is the following:
var me = this;
setTimeout(function() { me.update(); }, 10);
That will ensure that when "update" is called, it will be called with this set correctly as a reference to your object.
Unlike some other languages, the fact that a function is defined initially as a property of an object does not intrinsically bind the function to that object. In the same way that if you had an object with a propertly that's a simple number:
maxLength: 25,
well the value "25" won't have anything in particular to do with the object; it's just a value. In JavaScript, functions are just values too. Thus it's incumbent upon the programmer to make sure that this will be set to something appropriate whenever a function is called in some "special" way.
You problem is that you use an object literal instead of an instantiated object
Try to do it this way instead:
var Game = function() {
this.initialize = function () {
if (canvas.isSupported()) {
sprites[0] = new Player();
this.update();
}
};
this.update = function() {
for (var i = 0; i < sprites.length; i++) {
sprites[i].update();
}
this.draw();
};
this.draw = function() {
this.clear();
for (var i = 0; i < sprites.length; i++) {
sprites[i].draw();
}
setTimeout(this.update, 10);
};
this.clear = function() {
canvas.context.clearRect(0, 0, canvas.element.width, canvas.element.height);
};
}
now use:
var myGame = new Game();