Reputation: 13397
I have a class set up like this:
.factory('DesignerService', function () {
var kit = {
clubName: 'Moss side archery club',
teamName: 'The flying arrows',
selectedColours: ['082140', '841c3d'],
selectedGarments: ['hoody'],
selectedDesign: "Angelus",
total: '00.00',
templates: []
};
var getTemplates = function () {
var templates = [];
console.log(kit);
for (var i = 0; i < kit.selectedGarments.length; i++) {
var garment = kit.selectedGarments[i];
kit.templates.push('/assets/garments/' + garment + '.svg');
}
return kit;
};
var getColours = function () {
return ['000000', 'FFFFFF', '00adef', 'ed008c', 'fef200', '2e3192', '00a652', 'ed1b24', 'c7c8ca', 'f14e23', '6c9d30', 'c0d731', 'f5a3c7', '816ab0', '082140', '1e4f2f', '5bcaf5', 'f04e3f', 'f68b1f', 'cdbe01', 'ee4d9b', '007193', '5f1e08', '841c3d'];
};
var getGarments = function () {
return ['Shirt', 'Track top', 'Skirt', 'Hoody', 'Socks', 'Shorts', 'Track pants', 'Polo shirt', 'Beanie hat', 'T - shirt'];
};
var getDesigns = function () {
return ['Angelus', 'Claudius', 'Equitius', 'Octavius', 'Valerius']
}
var addToArray = function (array, item) {
array.push(item);
};
var removeFromArray = function (array, item) {
var index = array.indexOf(item);
if (index > -1) {
array.splice(index, 1);
}
};
var modifyArray = function (array, value) {
var i = array.indexOf(value);
if (i > -1) {
removeFromArray(array, value);
} else {
addToArray(array, value);
}
}
var setColour = function (colour) {
return modifyArray(kit.selectedColours, colour);
return kit;
};
var setGarment = function (garment) {
console.log(kit);
modifyArray(kit.selectedGarments, garment);
var kit = getTemplates();
console.log(kit);
return kit;
};
var setDesign = function (design) {
kit.selectedDesign = design;
return kit;
};
return {
kit: kit,
getTemplates: getTemplates,
getColours: getColours,
getGarments: getGarments,
getDesigns: getDesigns,
setColour: setColour,
setGarment: setGarment,
setDesign: setDesign
};
})
If I call the function setGarment the first console.log(kit) returns undefined so modifyArray errors at the kit.selectedGarments. But if I comment out the line:
//modifyArray(kit.selectedGarments, garment);
Then getTemplates actually logs the kit object and returns the updated object.
Can someone explain why?
Update 1
Ok, now I understand this hoisted stuff, I have redesigned my service to look like this:
.factory('DesignerService', function () {
var self = this;
var addToArray = function (array, item) {
array.push(item);
};
var removeFromArray = function (array, item) {
var index = array.indexOf(item);
if (index > -1) {
array.splice(index, 1);
}
};
var modifyArray = function (array, value) {
var i = array.indexOf(value);
if (i > -1) {
removeFromArray(array, value);
} else {
addToArray(array, value);
}
}
self.kit = {
clubName: 'Moss side archery club',
teamName: 'The flying arrows',
selectedColours: ['082140', '841c3d'],
selectedGarments: ['hoody'],
selectedDesign: "Angelus",
total: '00.00',
templates: []
};
self.getTemplates = function () {
var templates = [];
for (var i = 0; i < self.kit.selectedGarments.length; i++) {
var garment = self.kit.selectedGarments[i];
self.kit.templates.push('/assets/garments/' + garment + '.svg');
}
return self.kit;
};
self.getColours = function () {
return ['000000', 'FFFFFF', '00adef', 'ed008c', 'fef200', '2e3192', '00a652', 'ed1b24', 'c7c8ca', 'f14e23', '6c9d30', 'c0d731', 'f5a3c7', '816ab0', '082140', '1e4f2f', '5bcaf5', 'f04e3f', 'f68b1f', 'cdbe01', 'ee4d9b', '007193', '5f1e08', '841c3d'];
};
self.getGarments = function () {
return ['Shirt', 'Track top', 'Skirt', 'Hoody', 'Socks', 'Shorts', 'Track pants', 'Polo shirt', 'Beanie hat', 'T - shirt'];
};
self.getDesigns = function () {
return ['Angelus', 'Claudius', 'Equitius', 'Octavius', 'Valerius']
}
self.setColour = function (colour) {
return modifyArray(self.kit.selectedColours, colour);
return self.kit;
};
self.setGarment = function (garment) {
modifyArray(self.kit.selectedGarments, garment);
self.getTemplates();
return self.kit;
};
self.setDesign = function (design) {
self.kit.selectedDesign = design;
return self.kit;
};
return self;
})
Would this be the correct way to go about it?
Upvotes: 1
Views: 325
Reputation: 223104
Since you're approaching Angular factory from OOP side and referring to public 'class' member, it is a good practice to refer to it as this.kit
instead of kit
(they won't be equal if service's kit
property is changed). It also makes code unambiguous and readable.
The issue with local var kit
is classic JS hoisting problem, as Bill Bergquist's answer thoroughly explains.
Upvotes: 1
Reputation: 39297
You are encountering a hoisting issue.
In javascript you can initialize and use variable before they are declared.
x = "hello";
y = "world";
var x, y;
document.getElementById("message").innerHTML = x + " " + y;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="message"></div>
The declaration is hoisted but the initialization is not.
var x = "hello";
document.getElementById("message").innerHTML = x + " " + y;
var y = "world";
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="message"></div>
Functions behave somewhat differently. A function declaration can be used in code before they are declared, That is because they are loaded before any code is run, hoisted.
alert(works());
function works() { ... };
Function expressions are different. They are not loaded until they are reached in the code.
alert(doesntWork());
var doesntWork = function() { ... };
// Function declarations have their bodies hoisted.
document.getElementById("message1").innerHTML = y();
function x() { return "hello"; };
function y() { return x() + " world"; }
// Function expressions only load when the code is reached, they need to be declared before being used.
// document.getElementById("message2").innerHTML = b(); <-- This would cause an error.
var a = function() { return "hello"; },
b = function() { return a() + " world"; };
document.getElementById("message2").innerHTML = b();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="message1"></div>
<div id="message2"></div>
Upvotes: 1
Reputation: 263
This looks like a Javascript variable hoisting issue. The Javascript interpreter makes two passes through code. The first pass, it looks for variable declarations, and the second pass it executes the code. This is essentially doing the following to your code:
var kit = getTemplates()
becomes:
var kit;
kit = getTemplates();
At this point, the Javascript interpreter will make it's first pass, looking for variable declarations (var kit
). The next pass will actually execute the code (kit = getTemplates()
). Essentially, your code becomes:
var kit;
console.log(kit); // kit is undefined
modifyArray(kit.selectedGarments, garment); // kit is still undefined
kit = getTemplates(); // kit is no longer undefined
console.log(kit); // kit will log out properly here
return kit;
Hopefully this makes sense. The simple solution is to rename your scoped kit
variable to something else (maybe scoped_kit
). In general, it's best practice to not shadow variable names from one scope to another.
Hope this helps!
Upvotes: 4