Explanation asked about a Javascript / Angular line - javascript

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

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;
}

Angularjs does not recognize "this"

I have a modal whose contents is generated by an JavaScript method (the reason being that the contents strongly depends on data retrieved from the DB, including hierarchy and its structure).
Initially, I had checkboxes deployed (as part of the generated HTML) as follows:
<input type="checkbox"
id="Chkbox_1"
onClick="Handle_Select(this,1,'Topic_34343')">
and, within the javascript (in Handle_Select) I could verify if the checkbox was checked or not by testing this.checked as follows:
Handle_Select = function (p_this,p_Topic_ID, p_Topic_Name) {
if(p_this.checked) {...}
}
Now, I replaced the onClick by ng-click (as stated, I'm using AngularJS) and suddenly this no longer holds the properties of the input element but what appears to be the contents of the controller. Of course, the same function now looks:
$scope.Handle_Select = function (p_this,p_Topic_ID, p_Topic_Name) {...}
It is better to use this syntax:
<input type="checkbox"
id="Chkbox_1"
ng-click="Handle_Select($event, 1, 'Topic_34343')">
Angular code will be:
$scope.Handle_Select = function ($event,p_Topic_ID, p_Topic_Name) {
var target = $event.target;
if (target.checked) {
// some code
}
}
Angular comes with some handy directives that abstract a lot of the typical javascript boilerplate code. In this case, consider using the ng-model and ng-checked directives. ngModel will bind your input element to a value defined on your scope, and ngChecked will check or uncheck the input depending on a property you define:
<input type="checkbox"
id="Chkbox_1"
ng-model="your_scope_data" ng-checked="your_scope_data.is_checked">
so define $scope.your_scope_data in your controller, and then angular will tie it together with your template so that the values stay in sync. your_scope_data.is_checked is an arbitrary property of the data you bound with ng-model to the input element. You can also evaluate a simple expression in ng-checked if you want to perform comparisons, etc. Hope this helps, and good luck!

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

Angular isUnchanged - why doesn't this always work

I've seen this function used in several examples for form validation but can't find any info/docs/api for it and seems not to work in all cases. Is there an alternative for checking has the object changed ?
I have seen the method in AngularJS tutorials, and its just a custom function
$scope.isUnchanged = function(user) {
return angular.equals(user, $scope.master);
};
The above check i believe is reference match not the complete content.
You can use $watch method to watch any change on object. Also go through FormController it has properties like $pristine, $isDirty etc which is specific to form editing. I believe these values are also available on form elements.

AngularJS Directive - re-run link function on scope parameter change

I have a directive that builds a set of nested <ul> elements representing a folder structure. I used the link function to create the new DOM elements and append them to the directive instance element:
function link(scope, iElement, iAttr) {
var rootElement = buildChildElement(scope.tree);
iElement.append(rootElement);
}
Elements within the <ul> tree are wired with jQueryUI's drag/drop interactions that call a function on the Controller housing the directive to update the scope parameter based on the drag & drop events.
I would like the <ul> tree to automatically update when there is a change to the scope parameter. I have tried a watch function within my link function:
scope.$watch('tree', function(newTree, oldTree) {
var newRoot = buildChildElement(newTree);
iElement.contents().remove();
iElement.append(newRoot);
}
This works to a certain extent, but the call to remove() fires off the $watch() method a second time which ends up reverting my Controller changes. If I comment out the remove(), I can see that a new <ul> tree is written that properly reflects the changes to the parameter made in the Controller.
The double firing $watch() makes me think I'm going about this wrong. Without it, my parameter is properly updating but my <ul> doesn't update (the dropped element stays where it was dropped).
What's the correct way to make sure your directive is refreshed on a change in one of the scope parameters?
Should I be using the compile function and building the <ul> tree based on the attributes array instead of using the link function?
Your approach is very jQuery-style. I think you'll find that you're working against Angular in this case. sh0ber is right with his/her question; you should post a demo or something, or at least some sample code so you can have an effective answer.
I think you want to make a recursive tree directive. Check out this SO answer for some interesting approaches to this. The main idea is that watch is unnecessary. Simply change the object and Angular will take care of the rest. The most efficient thing is to change the specific node objects directly rather than replacing the whole object, but that will work too.
scope.$watch('tree', function(newTree, oldTree) {
var newRoot = buildChildElement(newTree);
iElement.contents().remove();
iElement.append(newRoot);
},**true**)
I think you can have a try and reference the watch API for more information
Here is another artical
http://www.bennadel.com/blog/2566-scope-watch-vs-watchcollection-in-angularjs.htm

Categories

Resources