Angular 4 DOM Manipulation and Search - javascript

Angular has these for DOM manipulation but I'm contemplating using jQuery for these functions: closest()/children().
So,
Is there an angular function that is identical to jQuery's function closest() which basically just returns the element?
Are there any alternatives for these functions in Angular without resorting writing native JS/TS operations to achieve those things just like jQuery, which does the dirty work? Or is alright to proceed with jQuery (I'm not dealing with template manipulation anyway)? Thanks.
Update
The window.getComputerStyle could easily replicate jquery's css().
Regarding jquery's selector: closest()
<div id="ample" #zero>
<div id="xample" #first>
<div #x>
</div>
<div #y>
</div>
</div>
</div>
I would like to know what could be an alternative operation for Angular. I could only think of making a function that traverses upward which jquery already does -give or take the DIVs and the element id are dynamically added/changed/deleted.
For example, from #y I want to know its nearest parent with an ID of ample. We know that the target element has a selector of #zero but retrieving it from div #y will take DOM traversal (which jquery simplifies using closest()) or some mapping/array operations that sorts out relations of the element which may be arduous in some point.

Is there is, one should avoid using jquery in Angular, here is an example how:
#Component({
selector: 'sample',
template: `
<span #tref>I am span</span>
`
})
export class SampleComponent implements AfterViewInit {
#ViewChild("tref") tref: ElementRef;
ngAfterViewInit(): void {
// outputs `I am span`
console.log(this.tref.nativeElement);
}
}
The keywords for you to search would be Elementref and Viewchild

JQuery is very powerful compared to what Angular is exposing for DOM manipulation. Sometimes it's very useful and very hard to ignore in an Angular application.
You can install it in your project but the only problem is that jQuery can access the DOM globally without encapsulation, so if you want to use good practices you should only access/modify DOM of the component you are using jQuery in, if you want to access/modify DOM outside of a component, you should pass needed data as #Input or use events to notify other components as #Output.
Do not forget to declare the variable $ in your component if you have installed it globally because typescript does not know what $ is.
declare var $ :any;

Using Jquery is not the angular way, but there are certain times where our hands are tied, only in those situations use jQuery. Use #viewchild or #viewchildren to get the DOM element.
span My name is XXX #name >
In .ts file
#ViewChildren('name') components: QueryList;
console.log(this.components.toArray());
You will be able to get the DOM. If you want only DOm element use #viewchild. In case of #viewchildren it will return an array of all the DOM elements which use the same selector or template reference variable.

Related

Can i use queryselector in angular 9 application

QuerySelector is part of typescript or javascript. Can I use this in my angular application Which one needs to use instead of QuerySelector in angular application. Why I am asking, Suppose generating dynamic HTML on that condition I want to handle some event on the dynamically generated HTML.
On that condition, querySelector is very easy. But some people are telling like do not to use quesrySelector that is not good practice. So, How to handle these issue?
document.querySelector(".myclass");
document.querySelector("ul").querySelectorAll('li');
In order to dynamically render content you can use structural directive like *ngIf
<div>
<p *ngIf="displayElement; else showThis">Content</p>
<ng-template #showThis>
else content
</ng-template>
</div>
querySelector it's not a good practice in Angular.
Instead of using querySelector or similar from there, a declarative way can be used instead to access elements in the view directly:
<input #myname> // html
#ViewChild('myname') input; // add this in ClassComponent
ngAfterViewInit() {
console.log(this.input.nativeElement.value); // Input will be available in this lifecycle
}

What is the valid selector type for `selector` property in angular2 component

I'm reading in a book about selector property of a component that:
With the selector key, you indicate how your component will be
recognized when rendering HTML templates. The idea is similar to CSS
or XPath selectors. The selector is a way to define what elements in
the HTML will match this component. In this case, by saying selector:
'inventoryapp', we’re saying that in our HTML we want to match the
inventory-app tag, that is, we’re defining a new tag that has new
functionality whenever we use it.
So I put in CSS selector
#Component({
selector: 'span[my-app].z',
template: `<h1>Hello {{name}}</h1>`,
})
and it worked.
So I'm interested to know if the full CSS selectors syntax is supported.
Short answer: Yes.
According to angular2 docs: https://angular.io/docs/ts/latest/guide/cheatsheet.html
Directive configuration:
selector: '.cool-button:not(a)'
Specifies a CSS selector that identifies this directive within a template. Supported selectors include element, [attribute], .class, and :not().
Does not support parent-child relationship selectors.
Note: The usual way to define a component selector is just by giving it a tag as you know. Like: selector: "my-component" and use it as <my-component> inside the html.

Get Elements with AngularJS without referencing the document

I have been developing an advanced web-based GUI in AngularJS. Recently, I decided to use the call document.getElementsByClassName() (I hate using element collecting methods, but here I had to use one) and my boss flipped his lid for accessing the document element. He says that I "need to use only Angular calls for everything", even for element collection! Is there an "Angular way" to collect elements by class name? If so, which way is better to use within the Angular framework? Please provide reasons why. Thanks!
UPDATE: Why I need to use an element collector...
So, I really wish I didn't have to do this, but I do...
I am using a third-party directive that I found online called the Bootstrap DateTimePicker. Its pretty cool and very nice looking, yet it might have a bug...
First, I make a directive bound to an attribute, stating that the element I pass in is meant to be a "DateTimePicker". I then pass that element to the DateTimePicker function.
When invoked, this function creates a new div with absolute positioning and appends it to the body of the page.
Now, I open a dialog in my GUI that has a table in it. On each row of the table, I have two DateTimePickers: one for end-date and one for start-date.
My problem is that, once I leave my screen and the elements which the DateTimePickers were bound to are destroyed, the DateTimePickers still remain! If I open the dialog box again, it creates a ton more of these divs as well!
Until I could determine a true solution to this issue, I decided to use the element collector as a temporary quick-fix. I grab all of the elements with the datetimepicker class and perform a:
elem[i].parentNode.removeChild(elem[i]);
Not having your exact use case but knowing that you are attempting to aggregate elements by class name in your controller makes me agree with you boss. Think of the controller as an object which exposes data and and services to your declarative html page. The data is bound into the markup for presentation and possible modification. THe services are usually wrapped in functions on your controller which are then tied to event handling directives like ng-click or ng-change. These services should operate exclusively on your data and never touch the DOM. If you need to modify a DOM element in your declarative markup then that should be done through directives like ng-class etc.
In any case, It would be useful to know what you are trying to accomplish so as to give you a better idea of the "angular way" to approach the problem.
Well, I have my answer. This does not solve the question "Grab all elements with a certain class name without touching the document element" yet it does solve my problem and eliminates my need to use document.getElementsByClassName.
First of all, it turns out that every element using the DateTimePicker directive have an element.datetimepicker("remove") function.
I use a directive for each DateTimePicker:
components.directive('DateTimePicker', function() {
// Requires bootstrap-datetimestamp.js
return {
restrict: 'E',
replace: true,
scope: {
dateTimeField: '='
},
template:
'<div>' +
'<input type="text" readonly data-date-format="yyyy-mm-ddThh:ii:ssZ" data-date-time required/>'+
'</div>',
link: function(scope, element, attrs, ngModel)
{
var input = element.find('input');
input.
datetimepicker(
{
//stuff
})
.on('changeDate', function(ev)
{
//more stuff
});
...
Directive drastically shortened for the sake of your eyeballs...
I then need to remove the DateTimePicker and the input it is bound to from the DOM on destruction of the dialog box that the input is a child of. To do so, I added this to my directive:
scope.$on("$destroy",function handleDestroyEvent()
{
input.datetimepicker("remove");
input = null;
});
And it works! The DateTimePicker gets removed, the DateTimePicker's handles to the input are cleaned up, and I've marked my input for the GC! WooHoo! Thanks everybody!
If you include jQuery in your project before AngularJS, Angular will use jQuery instead of jqLite for the angular.element function. This means you should be able to use jQuery's selectors for finding / referencing DOM elements.

Applying a javascript function on a div

I want to put a variable on a div and to be applied and inherited by all the dojo widgets under this div.
Is this feasible ?
For example
<div shaper="Contextual">
<textarea ..../>
<select multiple data-dojo-type="dijit/form/MultiSelect">
....
</div>
I want the functionality supported by the shaper to be applied to all the widgets included in the div.
p.s.: "shaper" is a custom module created to do numeric shaping for Arabic numbers.
It's possible, but not out of the box.
You can write something like this:
require(["dojo/query", "dojo/domReady!"], function(query) {
query("[shaper]").forEach(function(shaper) {
});
});
This will query all elements with a shaper attribute and loop over it. Inside the loop, you will have to retrieve the value of the shaper attribute (for example Contextual), you can do that with the getAttribute() function, for example:
var shaperModule = shaper.getAttribute("shaper");
Now you have the name of the module to load, so you can write something like this inside the loop:
require([shaperModule], function(shaperModule) {
});
This will use AMD to retrieve the Contextual module. Now all that's left is to include the shaper functionality into all widgets inside your <div>.
First of all, with dijit/registry::findWidgets() you can retrieve all widgets inside a specific DOM node, you can use this to retrieve your dijit/form/MultiSelect widget in this case:
registry.findWidgets(shaper);
Then you can loop over the array of widgets that are found and use dojo/_base/lang::mixin() to extend an object with the contents of another object, for example:
registry.findWidgets(shaper).forEach(function(widget) {
lang.mixin(widget, shaperModule);
});
For example: http://jsfiddle.net/zLv7cvzt/
Though this might not work entirely (what if the module does not exist or what about widgets inside widgets, which dijit/registry::byId() does not detect), it does give you an idea of how to achieve it.
To answer your second question, if it's feasible or not, I would say that it depends. If you extend a widget with another widget like this, it could really end up with really weird things, because all widgets extend from dijit/_WidgetBase, which provides the widget lifecycle, you could mix both widgets their lifecycle.
Also, if you end up doing this and you get an error, it will be really hard to debug this if you're not familiar with the custom code.

What is this.$() in Ember or JQuery

I saw example code on https://github.com/lukemelia/jquery-ui-ember. Can some one tell me what is this.$()
you can see this on jquery-ui-ember-master\jquery-ui-ember-master\js\app.js
this.$() is a call of the $-method of your current objectscope.
this refers to your current object.
$ is a function of this.
() will call the function $ of this.
When you create a Component, in its code this.$() gives you a jQuery object reference, set to the element that was inserted into the dom by that Component (its outer tag, usually a div unless you told it otherwise). You can then use for example this.$('.myclass') to find the element with the class myclass within the section of HTML that is handled by that Component without having to specify an id attribute to find the correct set of elements.
This probably also applies to the Views, but you should be using a Component instead whenever possible.
As Leeft said this.$() will give you the reference to the jQuery object, but typically you should only want to get the reference to the jQuery object in didInsertElement where the component has been inserted into the DOM and you can do jQuery-UI stuff on the element.

Categories

Resources