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.
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
Knockout version: 3.5.1
I have a custom element on my main .html file like so:
<my-component></my-component>
Inside I have a form to which I am attaching jQuery validation which is not working because when the line $("#myForm").validate is called, the form is not yet in the DOM.
I created a very basic jsFiddle to illustrate the issue: https://jsfiddle.net/sb1of04g/
Notice how if you remove the timeout, the result is 0. I get the same result if I move the alert below ko.applyBindings(new Test());
I want my jQuery validation code to run after the component is 100% loaded.
In my project I'm using custom elements and requirejs/text so to fix the issue I tried the below approach:
<my-component data-bind="event: { descendantsComplete: $root.OnComponentReady() }"></my-component>
self.OnComponentReady = function()
{
$("#myForm").validate ...
}
But no luck, OnComponentReady is executed correctly but the form is still not in the DOM.
This is when things got funny. Inside my-component I have another component, footer-component which is at the very bottom of the parent component and if I change my code to the below, I get the correct behaviour.
<my-component></my-component>
<footer-component data-bind="event: { descendantsComplete: $root.OnComponentReady() }"></footer-component>
Like this, when OnComponentReady is executed the form is available and I can attach jQuery validation to it. It also works if I move footer-component at the top of my-component.
I was under the impression that descendantsComplete fires after the component finished loading, similarly to jQuery's $(document).ready. Is this not the case? I'm not entirely sure I will have a child component in the future so ideally descendantsComplete is attached to the parent component.
Edit: I just realised that if I move the .validate code from my main ViewModel($root) to the Component ViewModel, I get the correct behaviour without the descendantsComplete event.
Update from 01.2020: It should be fixed with https://github.com/Polymer/lit-element/pull/712
If undefined returned from render method of LitElement during the first render of the component and then lit-html TemplateResult is returned with some css classes (styles are defined in styles static getter method), these styles are not applied.
There is a simple JSFiddle to reproduce this issue.
If render method returns lit-html TemplateResult after first render of component, then <style> tag exists in shadow DOM.
If render method returns undefined after first render, <style> tag is missed in shadow DOM and never added even if lit-html TemplateResult in next render call.
For Chrome it works fine. The issue reproduces for Safari and Firefox.
UPDATE: It should be fixed with https://github.com/Polymer/lit-element/pull/712
The solutions is to make sure you always return lit-html TemplateResult from render method even if it's empty!
render() {
return html``;
}
But I don't fully understand why exactly this issue appears? Could somebody clarify?
There are three separate cases of how styling is handled based on Shadow DOM support, via source code:
(1) shadowRoot polyfilled: use ShadyCSS
(2) shadowRoot.adoptedStyleSheets available: use it.
(3) shadowRoot.adoptedStyleSheets polyfilled: append styles after
That's why it can behave differently in different browsers.
LitElement has a method adoptStyles(). It applies styling to the element shadowRoot using the static get styles property.
In your example, you could call this.adoptStyles(); after changing the property and it should render correctly.
https://wicg.github.io/construct-stylesheets/#using-constructed-stylesheets
https://github.com/Polymer/lit-html/blob/master/src/lib/shady-render.ts#L127
Anyhow, I think you faced a bug within the update method of LitElement.
This could solve it: https://github.com/Polymer/lit-element/pull/849
I have an Angular 1.5 component with a controller (which uses controllerAs syntax), where I wrote a function adding additional css class to the component element if a certain html element exists in the page. If this certain html element doesn't exist, this additional css class is not applied on the component. That works in the pages where the html element which I am looking for, exists. However, when switching to another state, the component keeps the additional css class no matter that the html element doesn't exist on this state. You have to refresh the app in order to 'reset' the function which comes from the component's controller. This component is used on every page in the application.
For example, this is my component:
function myComponentController() {
activate();
function activate(){
addAdditionalCssClass();
}
function addAdditionalCssClass(){
// code for adding additional css class to the component
// if html element exists
}
}
It works fine when we are on a state where this html element exists. However when we go to another state, where the concrete html element is null, the function addAdditionalCssClass() continiues to add additional class to the component. Any help/suggestions would be greatly appreciated.
As I understand, you have a page with some dynamic html and a component in this page that should reflect the current state with a change in its classes.
One solution would be to have the component depend of a list of classes, i.e. have in its bindings a classes attribute, e.g.
.component('classSpecial', {
template: "<div ng-class='$ctrl.classes'>Hello</span></div>",
bindings: {
classes: '<'
}
})
See a simple example here, where you can change the classes of a component from the controller of the page.
This question demonstrates that overriding an Ember.View instance's didInsertElement allows you to execute some code after the view's element is in the DOM.
http://jsfiddle.net/gvUux/2/
Naturally, overriding didInsertElement on the child view class you add to an Ember.CollectionView will run the hook after each child view is rendered and inserted.
http://jsfiddle.net/BFUvK/1/
Two collection-oriented hooks on Ember.CollectionView, arrayDidChange and contentDidChange, execute after the underlying content has changed, but they execute before any rendering takes place. arrayDidChange is executed for every element added to the array, and contentDidChange wraps the content binding.
I would like to be able to hook around the rendering pipeline, something like willInsertCollection and didInsertCollection, to manipulate the DOM before and after all child elements are rendered - essentially, before and after filters around contentBinding.
Any ideas? I'm stumped.
If you want to want to do something before and/or after a view has been rendered you should use willInsertElement and/or didInsertElement respectively. In this case, since you want "to manipulate the DOM before and after all child elements are rendered" you should call those on your CollectionView.
I'm not quite sure what you mean by "before and after filters around contentBinding", so if this doesn't answer your question if you could clarify I'd be happy to help.
jsFiddle if needed
I wanted to apply a scroll animation to slide a list up after pushing new objects. The list was rendered using an ArrayController and the #each helper. Simply triggering an event on the controller which the view subscribed to after pushing objects was causing the animation to execute before the changes to the content were actually rendered. The following technique worked perfectly for me.
//excerpt from my loadMore method on the ArrayController
var self = this;
self.content.pushObjects(moreItems);
Ember.run.scheduleOnce('afterRender', this, function()
{
self.trigger('loadMoreComplete');
});