I have a multi-picklist component that houses a list of checkbox components. The parent component has a CSS :focus and :hover class for the mouseover. All controllable elements are in the tab index (so you can awkwardly use the keyboard to tab through the checkboxes).
Now we want to allow arrow-key navigation in the multi-picklist. Basically I need to use #ViewChild to grab the element I need and set .focus() to it. And that's exactly what I did in a different component, and that worked. However, here it does not work. The only difference is that in the component where it works my *ngFor loop iterates over a list of divs and in this case it does so over a list of components.
So what this boils down to is that I can't get the :focus pseudo class to stick to my component.The following code is not complete, just trying to get the first element focused. Sort of PoC.
MultiPicklist.component.html:
<div (keydown.ArrowDown)="arrowDownHit($event)">
<div [hidden]="multiPicklistState === 'collapsed'" (keydown.Escape)="closeBox()" #multiPicklist>
<app-checkbox
#checkboxItems
class="multi-picklist-checkbox"
*ngFor="let item of picklistItemList; trackBy: trackByFunc; let i = index;"
[fieldName]="item.value"
[label]="item.label"
[chckbxId]="'multiPicklistChkbx'+title+i"
[tooltip]="item.tooltip"
[isChecked]="item.isChecked"
(checkboxChanged)="inputChanged($event)">
</app-checkbox>
</div>
</div>
MultiPicklist.component.scss:
.multi-picklist-checkbox:hover, .multi-picklist-checkbox:focus{
background-color: $multi-picklist-item-hover-bg-color;
}
MultiPicklist.component.ts:
arrowDownHit(ev){
ev.preventDefault();
this.multiPicklist.nativeElement.firstElementChild.focus();
}
It's worth mentioning that the :hover pseudo class works, hovering the mouse over the component gives it the correct background color. But not .focus(). Furthermore, no error is thrown,.
This is just a workaround, not an actual answer or solution.
I was able to set the focus of an HTML element inside the component. It resulted in an ugly little line of code:
this.multiPicklist.nativeElement.firstElementChild.lastElementChild.focus();
Of course in an ideal universe I'd be able to just apply the focus to the entire component, or whatever div the browser ends up seeing.
Related
I have a custom component in angular that i re-use everywere in my app. This is a button component and i call it like this where i want to use it: <app-delete-btn></app-delete-btn>
I want to set the attribute tabindex="1" to my component but it does not work.
This attribute gives a TAB order to specific html elements.
Upon inspecting this strange behaviour, and as of my understanding, tabindex works but you have to specify it for the parent and ALL the child components
So i did this and it worked:
Upon declaring my custom component in my html <app-delete-btn tabindex="1"></app-delete-btn> i gave him the tabindex
and then i had to add it in the app-delete-btn.ts button inside the component <button tabindex="1">Delete</button>
The problem is that i may re-use that button therefore i can't add the tabindex from within the component itself otherwise is going to apply everywhere i use it.
Finally my question is:
Is there a way when calling <app-delete-btn></app-delete-btn> to assing a tabindex property to all of it's childrens (and by childrens i mean the button delcared in the html of the component)?
Add this to your button :
#HostBinding('attr.tab-index')
tabIndex = 1;
This should do the exact same thing as this
<app-delete-btn tabindex="1"></app-delete-btn>
But automatically
I'm new to Nextjs, doing setup for a nextjs react project. I used create-next-app to initialize code base, then realized that there's a weird div tag with the class 'selection_bubble_root' right inside body. Its visibility is set to hidden but it still spares an annoying empty block.
Does anyone know about it? What is it for or how to remove it? Many thanks!!
Not sure what that is for, but there is a thing called bubbling and it is triggered for example when you have a clickable element inside another clickable element.
something like
<div class="item1" onclick="do1()">
<div class="item2" onclick="do2()">
<div class="item3" onclick="do3()">
</div>
</div>
So when you click on item3 it will execute do3() first, but then it will also execute do2() and do1() as long as you dont disable it.
So this is called bubbling, it goes up from child to parent and the bubble root is item1 (in this case).
Opposite effect is called capturing
Hi I am using an UI Library (forced to, company issue..) which provides an Angular component, which renders a form.
Now I want to disable all of the input fields an buttons inside this form. But the component of the library doesn't provide me the possibility to pass a parameter to change the status to read only.
Now I have no other option to do dirty DOM hacking. However it doesn't seem to work.
Here is my HTML of my own component, where I render the Library Component:
<component-of-the-library #formComponent></component-of-the-library>
Now inside my own components class I reference it:
#ViewChild('formComponent', {read: ElementRef}) formComponent: ElementRef;
However when I use the nativeElement feature and the querySelectorAll() function I don't see the button elements:
ngAfterViewInit() {
console.log(this.formComponent.nativeElement);
console.log(this.formComponent.nativeElement.querySelectorAll('button'))
}
The first line outputs the DOM of the library component. There I also see the buttons.
However the second line just returns an empty NodeList.
Am I missing something?
Instead of doing all these, come up with a div overlay and with the size of your form and make show or hide it based on your needs.
It will be easier than disabling each form inputs and buttons. Also the overlay is not the component but your div.
I able to read the DOM Nodes present in the child component from the parent Component using ViewChild() https://stackblitz.com/edit/angular-edmyur?file=src%2Fapp%2Fapp.component.ts
EDIT: I see another problem. AfterViewChecked gets called multiple times...
I found the answer myself. The problem is the LifeCycleHook. AfterViewInit works for your own component, but it doesn't wait for the child components to finish rendering.
When I use AfterViewChecked it works!
However I am still puzzled, that logging the nativeElement has always given me the correct DOM, even though it's still not rendered.
On the twitter login page, the label for input fields arrive inside input fields that uses a common trick with javascript/jquery. However, I went through a twitter source to figure out how they are doing that. I found onChange: it adds a class 'hasome' to a parent div and has a default text as a span, which never gets a property like display:none;.
I have tried to go through their HTML/CSS/JS but could not find their methods. Can someone please tell how twitter is doing that?
Edit
Twitter code:
<div class="placeholding-input username hasome">
<input type="text" class="text-input email-input" name="session[username_or_email]" title="Username or email" autocomplete="on" tabindex="1">
<span class="placeholder">Username or email</span>
</div>
Added twitter HTML in question. When we add some code, it only add one class 'hasome' in parent div. in firebug, I could not see any property assigned to class 'hassome'. My question is where is there code which is doing that or CSS if it is achieved by CSS.
While the hasome class is applied to the parent div, it's used in a selector that's setting CSS values on the child span. So in Firebug (or Chrome or IE's developer tools), you'll need to keep an eye on that child span, not the div, to see what's going on.
You should end up seeing the following rules applied, from the CSS file t1_core_logged_out.bundle.css:
.has-content .placeholder, .hasome .placeholder
{
font-size:0!important;
z-index:-1;
-moz-opacity:0;
opacity:0;
-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";
filter:alpha(opacity=0);
}
The part of the rule that ends up taking effect is the ".hasome .placeholder" part: when an element with style .placeholder has an ancestor with class .hasome, then various techniques are used to hide that child element. It's basically using a class on a parent to control styles of a child or descendant, which is a fairly common CSS technique.
It's just displaying an absolutely positioned span over the field, then hiding it as soon as anything is entered (and re-displaying it when the field becomes blank again). The immediate hiding is why it doesn't matter that the span obscures the field. Oddly, it doesn't look like they actually used labels, although I don't see a good reason not to have.
Even though this is not what they are doing, you can accomplish the same result by using the HTML5 attribute placeholder
Keep in mind that this is supported by most major browsers with the regular exception of IE. So if this is not a concern for you, you can definitely use this.
It's CSS.
http://a0.twimg.com/a/1347042098/t1/css/t1_core_logged_out.bundle.css has the following rule:
.hasome .placeholder{font-size:0!important;z-index:-1;-moz-opacity:0;opacity:0;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";filter:alpha(opacity=0);}
Notice that for any .placeholder in a .hasome, its opacity is set to 0. Therefore, it doesn't show.
Not the way I would have done it, but that's how they're doing it at least.
I've found a couple of search results here but they're all for jQuery and the couple I looked at weren't applicable to my case.
This is a small project and I've avoided using jQuery so far. I want to keep it like that as to not need the library.
Basically, I'm dragging an <article> element to a <div> element. The div has the background-image of a closed trashbin. In the CSS it is set to display the same, but open, trashbin when :hover is triggered.
Now, when I pull my article element to the div, the :hover effect isn't being triggered.
How do I do this?
All required elements are set draggable and the needed event listeners have been added, Console.log confirms they work.
You can define a CSS class called 'open_trash' and set the background image of a open trash there and then you can use javascript to change the class of the dragged element on mousedown like this
document.getElementById("draggedItem").className = "open_trash";
You can set the class name to either an empty string or something else onmousedown.