What is the significance of '?ngModel' when creating an AngularJS directive? - javascript

I'm working my way through the new ng-book. The chapter on filters includes a section on defining parsers with the following code:
angular.module('myApp')
.directive('oneToTen', function() {
return {
require: '?ngModel';
The first time I've seen the '?ngModel' syntax, and the Angular API docs don't provide much help. What does this syntax signify?
Thanks!

? is optional directive and ^ is parent directive
http://docs.angularjs.org/api/ng.$compile
(no prefix) - Locate the required controller on the current element. Throw an error if not found.
? - Attempt to locate the required controller or pass null to the link fn if not found.
^ - Locate the required controller by searching the element's parents. Throw an error if not found.
?^ - Attempt to locate the required controller by searching the element's parents or pass null to the link fn if not found.

The Required can be explained as:
[?][^][directiveName].
It is used to specify which directive controller should be used("inherited from"). So for instance a directive <column-item> needs to find the parent controller <crtl-grid>. There are a couple of symbols that can be used along with this attribute and they can also be combined:
^ = it indicates angular to seek up the DOM to find the directive.
? = it indicates angular that the directive is optional and angular will not throw an exception if not found.
So ?ngModel is saying that the ngModel needs be declared along with this directive.

Related

Angular Js : How to get input value using AngularJS functions

I want to access form input value in services.
var emailId = document.getElementById("save_quote_email").value;
console.log("emailId="+emailId);
console.log("emailId2="+angular.element('#save_quote_email').val());
I am able to get value using document.getElementById("save_quote_email").value but not using angular function angular.element('#save_quote_email').val()
It gives error
Error: [jqLite:nosel] Looking up elements via selectors is not supported by jqLite! See: http://docs.angularjs.org/api/angular.element
http://errors.angularjs.org/1.2.16/jqLite/nosel
Please view this plunker http://plnkr.co/edit/Op1QDwUBECAosPUC7r3N?p=preview for complete code.
in dtoresource.js line numbe2 21.
You can't use angular.element to select by id or some other selector Link provide by you give full info as below
"Note: Keep in mind that this function will not find elements by tag name / CSS selector. For lookups by tag name, try instead angular.element(document).find(...) or $document.find(), or use the standard DOM APIs, e.g. document.querySelectorAll()"
you may use document.query selector as follow
var queryResult = document.querySelector('#save_quote_email');
var emailId2 = angular.element(queryResult);
Here is working plunker http://plnkr.co/edit/mC0JKTZpdnvqyBpihLRW?p=preview
Also this https://stackoverflow.com/a/23626251/5621827 will help you to understand it batter
Instead of trying to answer your question I am going to rather direct you to the correct way of using Angular.
You should never try and select input values, that is what ng-model is for.
ng-model bind the input to a value. As soon as the value changes Angular automatically updates the scope value, no functions of getting data necessary.
I can't make heads or tails out of your plunkr code but you should not do this:
var queryResult = document.querySelector('#save_quote_email');
Also you are trying to access the DOM from a factory, you should rather pass the needed value to an exposed function of the factory and call the function in your controller.
In your controller autoQuoteCtrl you should use a simply scope value for your input like so:
$scope.email = "";
And in your index the input should read:
<input type='text' ng-model="email" />
{{ email }}
Do not use convoluted variables like AutoQuote.postAutoQuoteObj.ApplicationInfo.GeneralPartyInfo.ContactInfo.Emails[0].EmailAddress in your scopes, you should assign the values when they are received from the resource.
$http({url: url}).then(function (rs) {
$scope.email = rs.postAutoQuoteObj.ApplicationInfo.GeneralPartyInfo.ContactInfo.Emails[0].EmailAddress;
}

Accessing scope params of children directives

I'm new in AngularJS, using it for two months in a project. I've learned how to use directives and theirs scopes (false, true, obj literal), but there's some questions about it...
First of all, we have some ng-repeats and directives with some behaviors, I tried to present a equivalent scenario in this link.
I didn't figure out how to access a function (testfn - within ng-controller) inside a directive child of another directive myItemDirective. But in myStepDirective it's accessible, I tried to pass it like in the first "layer" but didn't work.
PS.1: I created a myStepDirective with a isolated scope for other examples, if you need, just uncomment to test. Both I got a way to access params/functions from parent (controller), but not inside a grandchild.
Why directive's scope params doesn't work with camel case params? I don't remember to read some hint in AngularJS docs... typewithnocase inside myItemDirective works but typeList not.
Thanks!
EDITED]
For your 1. Here is a working fiddle working with limited scope and camel to snake case conversion : https://jsfiddle.net/wu0avqau/
I spend a loooooong time not understanding why it didn't worked but you juste forgot a = in your ng click inside your second directive
ng-click"testfn()"
For your 2. I can refer you to the documentation : https://docs.angularjs.org/guide/directive
Normalization
Angular normalizes an element's tag and attribute name to determine which >elements match which directives. We typically refer to directives by their case->sensitive camelCase normalized name (e.g. ngModel). However, since HTML is case->insensitive, we refer to directives in the DOM by lower-case forms, typically >using dash-delimited attributes on DOM elements (e.g. ng-model).
The normalization process is as follows:
Strip x- and data- from the front of the element/attributes.
Convert the :, -, or _-delimited name to camelCase."
basicaly your myItemDirective would be my-item-directive inside your template but still be myItemDirective inside your js.
Good luck,
Thibaud Lamarche

AngularJS : Why can't $interpolate render ng-style?

I have created a drop down input directive, where the user can pass in a template string to set what the list will actually render.
In my example I am passing in <div style="background-color: darkgrey" ng-style="{\'color\': isActive?\'red\':\'blue\'}">{{index}}</div> so it will render the items index number and then color it based on isActive. The index is show properly, and the background color is right but ng-style is being ignored.
I create the template in a setTimeout because I have to wait for ng-repeat to render the <li>.
setTimeout(function() {
var spanList = elm.find('li');
for (var index = 0; index < scope.list.length; index++) {
var listElm = angular.element(spanList[index]);
var listData = scope.list[index]
listElm.html($interpolate(scope.listTemplate)(listData));
}
}, 0);
I am iterating through the <li> elements and setting the template for each one. I am using $interpolate instead of $compile because using $compile would result in [[Object HTMLDivElement]] and I couldn't figure out why. From what I can tell $compile uses $interpolate anyways, and it works except that ng-style, ng-show, and ng-hide don't work. Why would angular's directives not work with $interpolate?
Here is the working example plunker.
$interpolate returns a function which returns a string. It is used to resolve {{bindings}}.
$compile returns a function which returns an html-element. It is used to compile raw (html) strings into html-elements and resolve angular-code inside of this string. $compile uses $interpolate to resolve any bindings inside this string.
In your case you probably want to use $compile and .replaceWith().
$interpolate is only for interpreting markup (example, "{{firstName}} {{lastName}}"):
AngularJS Documentation
$interpolate is a service used by $compile:
Compiles a string with markup into an interpolation function.
ngStyle, ngShow, etc do not rely on interpolation. Instead they rely on the $parse service to evaluate the AngularJS expression, and determine how to render the behavior.
$compile is appropriate in your scenario because it compiles the template HTML fragment by activating any directives within it, which indirectly calls $parse to evaluate expressions. Remember to append the template to the DOM before you $compile because directives may rely on parent directives higher up the DOM. I recommend the following pattern:
var e = angular.element(someTemplate);
element.append(e);
$compile(e)($scope);

How to know if $interpolate fails in AngularJS 1.2?

I'm trying to use the $interpolate service in AngularJS 1.2.16. However, I don't know how to check if Angular has properly interpolated all the vars in my string or not.
I noticed in AngularJS 1.3 they have added a new parameter AllOrNothing, which will cause the interpolate function to return an undefined if any embedded expressions fail to evaluate fully.
Any ideas how I can perform a similar check in 1.2? I would be okay looking for any embedded expressions, but Angular will strip them from the string if they are not specified in the context, so I can't even look for non-evaluated tokens in the returned string.
Use a unit test:
var exp = $interpolate('Hello {{name | uppercase}}!');
expect(exp({name:'Angular'}).toEqual('Hello ANGULAR!');
References
AngularJS Source: interpolateSpec.js

Explanation asked about a Javascript / Angular line

In a factory I construct a HTML page. This page can contain a form, so I want to get a handle on the FormController. After some Googling I've got everything working with this line of code (html is all the html in a string in a jquery selector):
html.find("input").eq(0).controller('form');
I understand that:
find(): it is going to find all the input elements;
eq(): I suppose this will select the first found item of the find list;
controller(): this part is unclear. I find it hard to find some documentation about this. What I do know is that you can pass ngModel or form. When passing ngModel you get the FormController of the specified control, thus not the whole form. And when specifying form you get a reference to the whole form.
So, I understand the most of, but I still don't get if controller() is an Angular function or Jquery function and how/when you can use this method.
There is no concept of "controller" in jQuery: controller() is obviously an Angular function. Here is the documentation:
controller(name) - retrieves the controller of the current element or its parent. By default retrieves controller associated with the ngController directive. If name is provided as camelCase directive name, then the controller for this directive will be retrieved (e.g. 'ngModel').
controller() is a method added by Angular to the jQuery object. It returns the Angular controller associated with the element. See the docs including other extra methods here...
http://docs.angularjs.org/api/ng/function/angular.element

Categories

Resources