Mootools: how to check child element? - mootools

HTML:
<ul id="mainmenu">
<li class="mainmenu-item">Menu 1
<ul class="mainmenu-child">
<li>Menu1</li>
<li>Menu2</li>
<li>Menu3</li>
</ul>
</li>
</ul>
JS:
$$('#mainmenu li').addEvents({
'mouseenter':function() {
alert(this.contains($$('.mainmenu-child')));
}
});
Always false.
Tried to use hasChild() method = same result, always false.
How to check has an element a child or not ? Need boolean type as a result.

this will work BUT:
$$('#mainmenu li').addEvents({
'mouseenter': function() {
var hasChild = !!this.getElement('ul.mainmenu-child'); // falsy/truthy.
console.log(hasChild);
}
});
The problem is, you use mouseenter on a matching li that also has children li that have their own event. so if you mouseover a child element, the mouseenter on the parent will also fire, so you will get a true and a false. you need to add extra checks if it's a root el or not etc.
checking if an element is there is simply requesting the element - if a match is found, it will return an object or null/undefined otherwise (falsy).

I think you can only check 1 element.
And if you're using a selector, just do this.getChildren(selector).length > 0

Related

why document.getElementsByName().length always return 0?

I'm new to JavaScript. In the following code getElementsByName("li").length always returns 0 although there are many <li>-tags in my HTML, why?
document.addEventListener('DOMContentLoaded', function() {
var len = document.getElementsByName('li').length;
alert(len);
})
art of my HTML:
<body>
<ul>
<li>aaaaaa</li>
<li>bbbbbb</li>
<li>cccccc</li>
</ul>
</body>
Replace
document.getElementsByName('li')
with
document.getElementsByTagName('li')
This is happening cause you are selecting by tag name and not by name ! You are using wrong function!
The method you are attempting to use is trying to find a specific element by its name.
None of your list items have a name, to do this you should update your code so that your items have names.
document.addEventListener('DOMContentLoaded', function() {
var len = document.getElementsByName('list_item_1').length;
alert(len);
})
<li name="list_item1">aaaaaa</li>
You can do something like this because getElementsByTagName() returns NodeList so you can iterate over it like an array or get the length.
document.addEventListener('DOMContentLoaded', function() {
var listElements = document.getElementById('list').getElementsByTagName("li");
alert(listElements.length);
})
<body>
<ul id="list">
<li >aaaaaa</li>
<li>bbbbbb</li>
<li>cccccc</li>
</ul>
</body>
getElementsByName() although also returns NodeList but it returns list of all same name elements in the whole document so to make this work you need to give same name to all list items.
document.addEventListener('DOMContentLoaded', function() {
var len = document.getElementsByName('name').length;
alert(len);
});
<body>
<ul>
<li name="name">aaaaaa</li>
<li name="name">bbbbbb</li>
<li name="name">cccccc</li>
</ul>
</body>

Show/hide child on parent click and grandchild on child click using CSS

I am displaying elements dynamically using Angular 6 *ngFor loop.
I have a three-level architecture.
I want to show inner elements on parent element click and innermost elements on inner element click in ul-li-a structure.
ONLY use CSS.
The active link gets the .activeLink class
<ul id="myUL">
<li *ngFor="let clientParent of sourceData;">
<a class="caret" routerLinkActive="activeLink" routerLink="..">{{clientParent.shortName}}</a>
<ul class="nested">
<li *ngFor="let clientFund of clientParent.counterpartyFunds" class="list-none">
<a routerLinkActive="activeLink" routerLink="..">{{clientFund.name}}</a>
<ul class="inner">
<li *ngFor="let fundAccount of clientFund.fundAccounts">
<a routerLinkActive="activeLink" routerLink="..">
{{fundAccount.shortName}}
</a>
</li>
</ul>
</li>
</ul>
</li>
</ul>
CSS:
a.activeLink {
color:red;
}
.nested {
display: none;
}
a.activeLink + ul {
display: block;
}
In a case like yours I would try to make components representing the "Parent" and the "Child" relationship.
In your Parent component template you render your Child component(s).
Additionally define a service like ShowChildrenService and inject this in your Parent components.
You update the ShowChildrenService through a click event on some parent (you can also pass the 'id' of the parent if you'd like). Each parent will listen to these events and decide wether they should render their children.
You can also let the parent pass a variable to its children, which in their turn set a CSS class via the [ngClass] directive.
Try this one, I used jQuery to toggle the your class nested"
if you clicked the parent list it will toggle between show/hide the child list.
jsFiddle: https://jsfiddle.net/cg9ruao1/
jQuery:
$('#myUL li').on('click', function (e) {
$('ul#list').toggleClass('nested');
});
HTML
I also added a ID for the ul with the class nested to be triggered.
<ul id="list" class="nested">

Best practice to change class on <li> and its child <a> upon click

I have a <li> element and I'm changing the css class of the <li> element upon click, using the ng-click (setting its controller highlighted holder variable) and ng-class (checking whether the <li> is highlighted in the controller and applying two types of classes for the true/false cases).
however I also need to change the class of the <a> which is a sub-element of the <li> based on the highlighting flag as I need a different text color.
do I create two ng-class tags for the <li> and the <a> inside of it and repeat the condition? or is there a better way?
I mean, it seems excessive to do this:
<li ng-click="navCtrl.setNav(1)" ng-class="{ 'nav_items_selected': navCtrl.isNavPage(1) , 'nav_items': !navCtrl.isNavPage(1) }"><a ng-class="{ 'nav_selected_a': navCtrl.isNavPage(1) , 'nav_a': !navCtrl.isNavPage(1) }" href="#">Dashboard</a></li>
You can use directive for changing the class of li and child a. I think its much better to use directive for handling DOM stuffs. it is also reusable for your future codes. documentation for directive: https://docs.angularjs.org/guide/directive
you can do something like this:
app.directive('changeClass', ['$location', function($location) {
return {
restrict: 'A',
link: function(scope, elem, attrs) {
elem.bind('click', function(event) {
var aChild = elem.children('a');
if(!elem.hasClass('active-li')){
elem.addClass('active-li');
aChild.addClass('active-link');
} else {
elem.removeClass('active-li');
aChild.removeClass('active-link');
}
});
}
}
}]);
html
<li change-class class="">
<a href="#" class="">
Dashboard
</a>
</li>
working demo here here
You can probably target your <a> in css without applying another class to it, since you've already done that to its <li> ancestor.
https://jsfiddle.net/tvbL877w/
Let's say you've got this css code:
.selected {
background-color: red;
}
.selected .some-child {
background-color: blue;
}
and your html is something like this:
<ul>
<li ng-class="{selected: myBoolean}">
Let's get some <a href="#" class="some-child" ng-click="myBoolean = !myBoolean" >CAKES!!!</a>
</li>
</ul>

Polymer: Capture events of child elements from parent

I was wondering how I can capture events which occur from a child element from the parent as shown below. I know this method works to capture events using this but I need it from the child element.
I don't want to capture the event from the li and transfer information to foo through global variables or other such means because I'll ultimately be implementing a mousemove event which sends the position of the mouse per trigger, and it would be extremely inefficient sending this through the global variables technique (like as demonstrated in the API here) and slow down the app.
<polymer-element name="foo">
<template>
<ul>
<li>This is my child element</li>
</ul>
</template>
<script>
Polymer('foo', {
ready: function() {
document.querySelector('li').addEventListener('mousedown', function() {
console.log('mousedown event working');
})
}
});
</script>
</polymer-element>
Thanks in advance for any insight you may provide.
Don't use document.querySelector() because your li element is inside the shadow dom of the Polymer element. Btw. the element name is incorrect, it must contain a dash.
You can use the automatic node finding feature of Polymer to get the li element. Assign an id to the element and use the this.$ property (alternatively if you don't want to assign an id, you can use this.shadowRoot.querySelector()):
<li id="item">This is my child element</li>
this.$.item.addEventListener(...);
But with Polymer you can declaratively assign the callback function to the li element, which results in a much more readable code:
<polymer-element name="my-foo">
<template>
<ul>
<li on-mousedown="{{mousedown}}">This is my child element</li>
</ul>
</template>
<script>
Polymer('my-foo', {
mousedown: function() {
console.log('mousedown event working');
}
});
</script>
</polymer-element>

Adding tabindex dynamically

I'd like to add tabindex to all form elements. The form is dynamic and I can't add it to the HTML. I would like to run it as a function.
If there are several radio buttons with the same name, each must have it's own tabindex value. Most of the form elements on page start as <input>, except <select>. How do I account for that?
I guess I will need to run a loop and add the attribute, right?
var n = 1;
$('input, select').each(function() {
$(this).attr('tabindex', n++);
});
Strange question, but yes that's the basic idea:
$(":input:not(:hidden)").each(function (i) { $(this).attr('tabindex', i + 1); });
This uses :input to get everything including buttons and text areas. :not(:hidden) will just exclude the hidden inputs to avoid unnecessary tabs.
Might be better to avoid n++ to set different tabindex numbers.
Instead, try setting tabindex to 0:
$(':input:visible').each(function() {
$(this).attr('tabindex', '0');
});
tabindex="0" means that the element should be focusable in sequential keyboard navigation, but its order is defined by the document's source order.
~ developer.mozilla.org
The :input selector basically selects all form controls.
The :visible selector basically selects all elements that are visible.
or as suggested in the comments, if you have no other changes to apply to each visible input, then this should be enough:
$(':input:visible').attr('tabindex', '0');
Here, I described how can add aria-selected and tabindex value dynamically via jquery. I also want to see that how accessibility work with tablist, tab, and tabpanel role and how aria attributes work.Hope helps this code :
var $tabs = $('.tabs');
var $panels = $('.panel');
$tabs.on('click', 'a', function (e) {
e.preventDefault();
var id = $(this).attr('href');
// Find the currently visible tab and panel and hide them
$tabs.find('[aria-selected="true"]').attr({
'aria-selected': false,
'tabindex': -1
});
$(this).attr({
'aria-selected': true,
'tabindex': 0
});
});
Tab Wrapper:-
<ul class="tabs" role="tablist">
<li role="presentation">Tab 1</li>
<li role="presentation">Tab 2</li>
<li role="presentation">Tab 3</li>
</ul>
<div class="tab-panels">
<div class="panel" id="tab-1" role="tabpanel" aria-hidden="false">…</div>
<div class="panel" id="tab-2" role="tabpanel" aria-hidden="true">…</div>
<div class="panel" id="tab-3" role="tabpanel" aria-hidden="true">…</div>
</div>
One approach is to move an element higher in the DOM. The element at the top of the DOM tree will be focused first using Tabs as compared to lower ones.
For what's it's worth, I don't think you actually need to use an each loop here or even $(this).
jQuery is configured to execute functional arguments in place of plain values and runs the function once per loop, similarly to how an each loop would work.
You can read more on how that works in the official jQuery documentation here: .val( function )
So rather than using an each loop, you can accomplish the same effect using just this:
let n = 1;
$(':input:visible').attr('tabindex', function() { return n++; });
or if you're okay using the modern ES6 arrow function syntax—
let n = 1;
$(':input:visible').attr('tabindex', () => n++);
Using () => n++ instead of just n++ here allows jQuery to run the function for each instance's value rather than taking in the initial value of n++ and applying it to all matching elements.