Code Highlighting in PHPStorm/WebStorm for Angularjs - angularjs

In my controller, I have a function defined as:
var ProductListingHeaderController = function (FilterService, CategoryService) {
this.isCategorySet = function () {
return (FilterService.categoryID);
};
this.categoryName = function () {
return (CategoryService.categoryName());
};
};
The IDE (via code highlighting) reports categoryName() as being used and isCategorySet() as unused.
This is kind of understandable, since:
categoryName() is used inside {{ }} in the html file:
<h2>{{productListingHeader.categoryName()}}</h2>
and isCategorySet() is used in an ng-if string:
ng-if="productListingHeader.isCategorySet()"
Given that this is such a common usage, I suspect I may be missing a setting in Storm as to how to set things up so that this type of usage (inside a string) by an Angular directive gets picked up as "used".
Thanks in advance for any feedback.

That's normal behavior for PHP/WebStorm.
Template -> JavaScript is really just an ambiguous connection. There is no support for jsDoc type inferring in the AngularJS templates. So PHP/WebStorm will match a template function call to JavaScript if only that function name is unique.
PHP/WebStorm have issues inferring closure methods as object functions. I've had better success using prototype declaration for AngularJS controllers.
var ProductListingHeaderController = function (FilterService, CategoryService) {
this.filterService = FilterService;
this.categoryService = CategoryService;
}
ProductListingHeaderController.prototype.isCategorySet = function () {
return (this.filterService.categoryID);
};
ProductListingHeaderController.prototype.categoryName = function () {
return (this.categoryService.categoryName());
};
Compare the above code with your code, and look at the structure explore in WebStorm. When you use prototypes for controllers they appear in the explorer properly.

Related

With Angular, should I bind to "domain command" functions (less abstraction) or GUI action handling functions (more abstraction)?

I searched several Angular style guides and best practices links, but I couldn't find a note on this issue. (Note, I am not using $scope.) If we have a ordinary web page with elements that invoke functions on the controller, my instinct from working with WPF was to do:
<button ng-click="myCtrl.save()">Save</button>
...
function myController(thingSavingService){
var ctrl = this;
// ...
ctrl.model.thing = {};
// ...
ctrl.saveThing() = function () {
thingSavingService.save(ctrl.model.thing);
}
}
Someone suggested that perhaps having element-specific handler functions is a good practice, like:
<button ng-click="myCtrl.onSaveClicked()">Save</button>
...
function myController(thingSavingService){
var ctrl = this;
// ...
ctrl.model.thing = {};
// ...
ctrl.onSaveClicked = function () {
saveThing();
}
var saveThing = function () {
thingSavingService.save(ctrl.model.thing);
}
}
Is binding these things directly to the function on the controller a good practice, or is it better to have another layer in between so that "action handlers" are separate from the domain-level functions?
In other words, with Angular, should I bind to "domain command" functions (less abstraction) or GUI action handling functions (more abstraction)?
Also, are there any articles or best practice guides that explore these nuances?
Personally, I follow John Papa's styleguide as for functions placing and abstraction level where he states to have pure functions below their assigning to controller. It's of course mainly for readability purposes.
function SessionsController() {
var vm = this;
vm.gotoSession = gotoSession;
vm.refresh = refresh;
vm.search = search;
vm.sessions = [];
vm.title = 'Sessions';
////////////
function gotoSession() {
/* */
}
function refresh() {
/* */
}
function search() {
/* */
}
}
https://github.com/johnpapa/angular-styleguide/blob/master/a1/README.md#style-y033
It is more about styling. In sitepoint there is this article StyleGuide which talks about styling guides.
As LIFT principle states that;
It is better do in this way
function myController(thingSavingService){
var ctrl = this;
ctrl.model.thing = {};
ctrl.onSaveClicked = saveThing;
var saveThing = function () {
thingSavingService.save(ctrl.model.thing);
}
}
Not because of performance, but because more readability.
As per your terminology, angular controller public method can be treated as "action handlers" and those are seperate from domain-level functions. When I say domain level functions, I am referring to Angular Services Functions/apis.

Why do i have to re-declare properties in typescript angular controller functions

export interface IFooModel {
foo:string;
fooFunction(fooProp:string):void;
}
export class FooCtrl implements IFooModel {
constructor(public foo:string){
}
fooFunction(fooProp:string):void{
}
}
The code above is fairly standard. My question is , when i want to access foo:string in the function i have to do this
fooFunction(fooProp:string):void{
var fooAgain = this.foo;
// Pretend i set it up properly for $mdDialog to work
this.$mdDialog.show(options).then(function(answer: boolean) {
if (answer) {
// fooAgain works
// this.foo does not work
}
}
Why do i have to set this.foo to a variable in order to access it inside another function , instead of just writing this.foo ? In some functions i end up for about 4 variables declarations that are already declared in the constructor. Is there maybe a better way to this? I get the feels that there is too much repeat code in the controller.
Yes this is a problem in Javascript, but thankfully in TypeScript this problem is no more thanks to fat arrows! Yay!
Fat arrows are like anonymous functions but handle the this variable for you.
Let me show you:
fooFunction(fooProp:string):void {
// Pretend i set it up properly for $mdDialog to work
this.$mdDialog.show(options).then((answer: boolean) => {
if (answer) {
this.foo = "";
}
});
}
Using fat arrows this will now compile to this in JS:
FooCtrl.prototype.fooFunction = function (fooProp) {
var _this = this;
// Pretend i set it up properly for $mdDialog to work
this.$mdDialog.show(options).then(function (answer) {
if (answer) {
_this.foo = "";
}
});
};
So Typescript automatically creates a _this variable for you, so that you no longer have the problem. Pretty neat if you ask me.
Here's the documentation for Arrow functions:
https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Functions/Arrow_functions
The only reason to place the value in a local variable prior to calling a function is because you expect the class to go out of scope (i.e. something will happen to change the scope, such as a callback or asynchronous operation).
By putting the value in a local variable it becomes part of the closure for the function and the value is stored alongside the function itself.
This is one of the trickiest aspects of JavaScript - scope is kinda funky.
There are other options to solve this problem, including fat arrows...
() => {
// this.foo is now preserved
}
Or call / apply which allow you to set the scope.

Creating child controllers

I'm not sure if I'm thinking about my problem incorrectly, but basically here it is: I have a pen and paper gaming site I've built in PHP that I'm converting to Angular. I have one particular set of pages (for character sheets, displaying and editing) that are hit, then based on URL parameters, instantiate one of a few dozen subclasses, and call a common function among them. This function displays the page according to that subclasses template and logic. Example:
URL: /characters/dnd4/5/
When someone hits /characters/(anything)/ the site looks up (anything) to see if its a valid system, and instantiates an object of class (anything)Character, which is a child of Character. Character has a method called displayEdit which in (anything)Character calls the correct template for that system. Then everything gets carried down: functionality common to all characters (or a set of characters) is shared by parent classes, which can go up 2-3 tiers before hitting Character.
In PHP, this was just a case of having everything hit a set of common parents, but basic logic for the page is in the Character class, and then specific actions in the child classes. I'm having trouble figuring out how to map this in Angular. So far, I've just been creating controllers that do the logic for their page; I'm not sure how to set this up for logic being split to other functionality. I thought about making each option a directive, but can a directive be called dynamically? Should I be creating JS classes that operate the same? Can they carry the $scope from controllers?
All in all, I'm just not sure how to tackle this, or I've just overthought this so much I can't see an obvious solution.
Class inheritance in JavaScript can be done in a few ways. Creating closures with private variables and returning accessor methods is one such way, as opposed to prototyical inheritance. In Angular, you can abstract all your class logic into a service, then pass it into your controllers which will create the relevant view by loading a particular template & populating the correct information. Here is an example of creating a base class, a couple of sub-classes, and a sub-sub-class. I did not include templates, as this is simply a matter of calling a particular template file (via ng-include or by directive), but the general idea is here.
Update: The more succinct, ES6 version of the code
// Module
angular.module('app', [])
// Service
function characterService () {
return {
character: function (spec) { // base class
var type = spec.type || 'untyped'
var name = spec.name || 'unnamed'
var stats = {
health: 10,
mana: 10
}
return {
getType: function () {
return type
},
getName: function () {
return name
},
getStats: function () {
return stats
},
setStats: function (newStats) {
stats = newStats
}
}
},
// sub class of character
elf: function (spec) {
spec.type = spec.type || 'Elf'
var elf = this.character(spec)
var stats = elf.getStats()
stats.health += 10
elf.setStats(stats)
elf.attack = function () {
return 'You have shot an arrow!'
}
return elf
},
// sub class of character
mage (spec) {
spec.type = spec.type || 'Mage'
var mage = this.character(spec)
var stats = mage.getStats()
stats.mana += 10
mage.setStats(stats)
mage.attack = function () {
return 'Woah! Magic missile!!'
}
return mage
},
// sub class of mage
warlock (spec) {
spec.type = 'Warlock'
var warlock = this.mage(spec)
var stats = warlock.getStats()
stats.mana += 10
warlock.setStats(stats)
warlock.attack = function () {
return 'Cthulhu is summoned!'
}
return warlock
}
}
}
//Register Service
angular.module('app').factory('characterService', characterService)
// Main Controller
function main ($scope, characterService) {
$scope.player1 = characterService.elf({name:'Erik'})
$scope.player2 = characterService.mage({name:'Aayla'})
$scope.player3 = characterService.warlock({name:'Zenthyr'})
}
// Register controller
angular.module('app').controller('main', main)

how to pass parameters on flow.upload in flowjs

I need to pass parameters which are different for each file I used flowobj.opts.query but that adds to all files. Parameters should be different for each file upload
angular.forEach($flow.files, function (file, key) {
file.flowObj.opts.query[file.DocumentName.concat("-DocumentName")] = file.DocumentName;
file.flowObj.opts.query[file.DocumentExtension.concat("-DocumentExtension")] = file.DocumentExtension;
file.flowObj.opts.query[file.DocumentType.concat("-DocumentType")] = file.DocumentType;
file.flowObj.opts.query[vm.case.Id.concat("-CaseId")] = vm.case.Id;
});
$flow.upload();
From the documentation:
**query** Extra parameters to include in the multipart POST with data. This can be an object or a function. If a function, it will be passed a FlowFile, a FlowChunk object and a isTest boolean (Default: {})
Therefore, just use a function instead of an object as you are doing. Have your function return the object that you want added as parameters.
Old post, but wasn't clear enough without an example for me.
So to assign parameters to each file, the best way is to pass a function to the query property that will be evaluate at each chunk, like stated in this issue on github :
var flow = new Flow({
query: function (flowFile, flowChunk) {
if (flowFile.myparams) {
return flowFile.myparams;
}
// generate some values
flowFile.myparams = {parameterName:'parameterValue'};
return flowFile.myparams;
}
});
So for angular it will be set in the provider like this:
var app = angular.module('app', ['flow'])
.config(['flowFactoryProvider', function (flowFactoryProvider) {
flowFactoryProvider.defaults = {
query: function(flowfile, flowchunk) {
if (flowFile.myparams) {
return flowFile.myparams;
}
// generate some values
flowFile.myparams = {parameterName:'parameterValue'};
return flowFile.myparams;
}
}
Can also be done in the directive flow-init, I assumed.

this point set to null using afterSelectionChange in ngGrid

I'm writing an application using angular and typescript.
I'm using ng-grid and I have to handle the afterSelectionChange event.
I tried to set the event handler in two ways
this.$scope.settoriGridOptions.afterSelectionChange = this.afterSelectionChange;
where this.afterSelectionChange is a method of the controller class,
and
this.$scope.settoriGridOptions.afterSelectionChange = (... ) => {};
including the code inside, but in both cases the this pointer is incorrect and I cannot access to the services of the controller.
how can I fix this?
after a more tests and reading a few articles I see that the problem is the implicit passing of the this pointer as parameter in the function call.
if I write
$scope.filtroSoluzione = this.filtroSoluzione;
when called the this pointer is set to null, but if I write
$scope.filtroSoluzione = () => { return this.filtroSoluzione() };
or
$scope.filtroSoluzione = () => { .. inline code ... };
the this pointer I set correctly.
How can I have a more consistent behavior? I don't like to write always the code inside because this makes the class harder to read and navigate
thanks,
Luca
Thanks for the extra information in your edits, I now see the problem.
class foo {
public afterSelectionChange = () => {
console.log(this);
}
}
When you declare your function like I did above, your this is the instance instead of what you are seeing know because it captures the this variable. It comes with a cost though, because now it creates a new afterSelectionChange function for every instance of your class. In this case I think it is still what you want though.
var foo = (function () {
function foo() {
var _this = this;
this.afterSelectionChange = function () {
console.log(_this);
};
}
foo.prototype.baz = function () {
console.log(this);
};
return foo;
})();
In the above code-gen you can see the difference when declaring the function with name = () => {} and the normal way.
Another solutions might be this:
this.$scope.settoriGridOptions.afterSelectionChange = this.afterSelectionChange.bind(this);
But I don't find that really nice either... (this should work with the normal public afterSelectionChange() {} declaration you are used to.

Resources