How to convert camelCase attribute name to angular's dashed-case attrubute - angularjs

I have a custom Angular service which creates a custom DOM node using angular.element(). Meanwhile, since I also want the element to have a set of predefined attributes, I pass a JS object as a second parameter to the function:
var element = angular.element('<node-name />', {
class: "some css class",
onclick: "someClickHandler()"
});
Although this works OK as far as the attribute is not specific to Angular.
The problem is that I'm not able to produce Angular-like dashed-case (don't know what their actual name is) attributes (e.g. ng-click).
For now, if I do:
var element = angular.element('<node-name />', {ngClick: 'someClickHandler'}); // ng-click here is definitely not possible as it leads to a syntax error
it will always result in the DOM node as:
<node-name ngclick="someClickHandler"></node-name>
which doesn't work the Angular way.
So, is there any way that a camel-case attribute be converted to its equivalent dashed-case in the DOM?
Any help would be appreciated.

You don't really need any additional code to convert from camelCase to snake-case (although you could). It's better to use snake-case in the first place if you really want to, just make sure you put property name in quotes, otherwise the name is not valid identifier:
var element = angular.element('<node-name />', {
'ng-click': 'someClickHandler'
});

Related

Is there a way to get the name of an ng-model from an element

I want to find the name of the model on the active element. Basically I have document.activeElement how do I find out what it's ng-model is.
<input ng-model="myModel">
So in the above control if that was active how would I be able to find out that we are in the element with the ng-model of myModel. This is technically a workaround for adding an id or a name, but I would rather not do it if I can
As an aside this code is in the controller not a directive.
Here is the Fiddle
You need to get the element object as discribed in the comment in the code and then access it with attr
// get element
var result = document.getElementsByTagName("input")[0];
// get object using jQLite or jQuery
var ele = angular.element(result);
// access 'ng-model' as 'attribute'
alert(ele.attr('ng-model'));
CAUTION: Here it's shown just for example considering just one input element. Use proper class/element/attribute selector to get proper element you want to target.
input/element In Angularjs will bind a ng-model.Without using id or classes to get the element DOM can use $('[ng-model="Model"]') But If the model is under ng-repeat.
if you write
and to get the element use $('[ng-model="name"]'), it will inject that particular element from the DOM.
With document.activeElement, you can access the list of attributes on the returned element like this:
var nameOfModel = document.activeElement.attributes['ng-model'].value;

Using element.find() by class in Angular Unit testing

When running this test, I keep getting the error Expected undefined to be true.
it('should have the right classes', function() {
// this doesnt work
expect(element.find('.exampleClass').hasClass('ng-hide')).toBe(true);
// but this works
expect(element.find('span').hasClass('ng-hide')).toBe(true);
});
How can I use jqlite to find an element by id and class?
That is because angular-jqlite (very lightweight library when compared to jquery itself) find is limited to look up by tag names only. You can use element.querySelector(All) and wrap it in angular.element. i.e
var elm = element[0];
expect(angular.element(elm.querySelector('.exampleClass')).hasClass('ng-hide')).toBe(true);
//Or even
expect(elm.querySelector('.exampleClass.ng-hide')).toBeDefined();
See documentation
find() - Limited to lookups by tag name

What does the "type" attribute of a directive do?

What does the "type" attribute of a directive do? I can't seem to find it documented.
Here's an example of its usage:
https://github.com/crudbetter/angular-charts/blob/master/src/piechart.js#L81
Does that usage just create an unused attribute, or does it actually have some sort of meaning?
The type attribute governs how the template is wrapped. Specifically, if it is svg or math it is wrapped in a div and a sub element of the type. Here is the function that leverages it inside the $compile service where the directive API lives from the source:
function wrapTemplate(type, template) {
type = lowercase(type || 'html');
switch (type) {
case 'svg':
case 'math':
var wrapper = document.createElement('div');
wrapper.innerHTML = '<' + type + '>' + template + '</' + type + '>';
return wrapper.childNodes[0].childNodes;
default:
return template;
}
}
It's now known as templateNamespace, and described as such in the docs.
As far as the AngularJS Directive Definition Object documentation goes, there is no mention to a "type" attribute whatsoever.
In the source you provided, they use the value 'SVG'. The only related attribute would be templateNamespace which corresponds to the document type used by the markup in the template.
AngularJS needs this information as those elements need to be created and cloned in a special way when they are defined outside their usual containers like <svg> and <math>.
Edit:
Well, I tried finding out if type works like templateNamespace but couldn't make any of them work (tried with Angular v1.3.2 and v1.2.1).
here's the fiddle

Reference to HTML elements in view, a convention?

I'm currently in the progress of learning Backbone.js and I'm using the book Developping Backbone Applications.
I have a questions about the reference to HTML elements and how they are stored. For example:
initialize: function() {
this.$input = this.$('#new-todo');
Here the HTML element with ID to-do is stored in the this.$input, why do we use the $ in front of input, is this merely a convention? If I change this.$input to this.input my code works fine. I find this confusing because the book states:
The view.$el property is equivalent to $(view.el) and view.$(selector) is equivalent to $(view.el).find(selector).
I would think that $(view.el) does something completely different than (view.el).
How is this.$input saved in Backbone.js? If I console.log it, it produces:
Object[input#new-todo property value = "" attribute value = "null"]
Could someone give me some insight? :)
Using $ infront of a variable name is just a naming convention. It helps developer in distinguishing variable holding jQuery objects from others.
view.$el is a helper variable provided by Backbone, so that we can use it directly, instead of explicitly forming the jQuery object. Hence view.$el is equivalent to $(view.el).
view.$el is assigned in setElement method:
setElement: function(element, delegate) {
// Some code
this.$el = element instanceof Backbone.$ ? element : Backbone.$(element);
// Some code
}
Backbone.$ is reference to $ global variable exported by jQuery.
view.$(selector) is a method defined in View. It's definition does exactly same as $(view.el).find(selector)
$: function(selector) {
return this.$el.find(selector);
}

Can AngularJS ngClass expressions be nested?

I'm new to AngularJS and have been assigned a maintenance task on an app we've inherited (originally developed for us by a third-party).
At the left of a header row in a table is a small button showing either a plus (+) or minus (-) symbol to indicate whether it will expand or collapse the section when clicked. It does this using ngClass as follows.
ng-class="{false:'icon-plus',true:'icon-minus'}[day.expanded]"
I have to remove the button when there is no data in the section and thus no ability to expand. There is already a class (.plus-placeholder) for this and I was wondering if the expressions that ngClass uses can be nested to allow something like this
ng-class="{false:'plus-placeholder',true:{false:'icon-plus',true:'icon-minus'}[day.expanded]}[day.hasTrips]"
which would allow me to add a hasTrips property to day to accomplish the task.
If this is not possible I think I will need to add a property something like expandoState that returns strings 'collapsed', 'expanded' and 'empty'. so I can code the ngClass like this
ng-class="{'collapsed':'icon-plus','expanded':'icon-minus','empty':'plus-placeholder'}[day.expandoState]"
And perhaps this is a cleaner way to do it in any case. Any thoughts/suggestions? Should it be relevant, the app is using AngularJS v1.0.2.
You certainly can do either of the two options you have mentioned. The second is far preferable to the first in terms of readable code.
The expandoState property you mention should probably be a property or a method placed on the scope. Your attribute would then read something like
ng-class="{'collapsed':'icon-plus','expanded':'icon-minus','empty':'plus-placeholder'}[expandoState()]"
To put this method on the scope you would need to find the relevant controller. This will probably be wherever day is assigned to the scope. Just add
$scope.expandoState = function() {
// Return current state name, based on $scope.day
};
Alternatively, you could write a method on the controller like
$scope.buttonClass = function() {
// Return button class name, based on $scope.day
};
that just returns the class to use. This will let you write the logic from your first option in a much more readable fashion. Then you can use
ng-class="buttonClass()"

Resources