How to access the style attribute of Primeng table - html

In an angular project, I need to test that the displayed table width of the primeng data table is set to the maxWidth value i assign to it. To do so, i want to call the [style] attribute to get the width and see if its equal to my maxWidth. However, i do not know how to call attributes like this. How do i go about this? Currently i have no clue if I'm going in the correct direction.
I have tried several things but I am not sure of the syntax for it.
<p-table class="p-table" ... [style] = "{width: maxWidth}" >
it('should implement maxwidth', () => {
const widthDebug: DebugElement = fixture.debugElement;
const tableWidth = widthDebug.query(By.css('.ui-table .ui-widget'));
const ptable: HTMLElement = tableWidth.nativeElement;
expect(ptable.textContent).toContain("width: " + component.maxWidth);
});
expected: success (ptable.textContent contains "width: component.maxWidth")
actual: TypeError: cannot read property 'nativeElement' of null

I see that it's now two months after you asked your question, so it's probably too late for my answer to help, but I stumbled across this post while looking up something else about PrimeNG, so I might as well give it a shot.
The problem here is that nativeElement is defined on Dialog class instances of the Angular p-table component. It's not defined on any particular DOM element.
By.css('.ui-table .ui-widget') is going to find a DOM element for you, not an Angular class instance. In particular what will be found is a <div> inside the <p-dialog> DOM element, and it's this <div> that receives the style set via [style]=....
As your code is written above tableWidth.style.width would contain (as a string) the value of maxWidth that you're expecting to find.

Related

Ionic3 - ElementRef nativeElement.getElementsByClassName returns collection but it is inaccessible

I'm following this tutorial about Ionic and directives and everything works fine except when I try to get the FAB element using ElementRef's nativeElement.getElementsByClassName, like this:
this.fab = this.element.nativeElement.getElementsByClassName('fab')[0]
That returns undefined. The problem is when I remove the index and print the whole HTMLCollection using console.log, it shows me a complete list with all the FAB's inside the element.
Running
console.log(this.element.nativeElement.getElementsByClassName('fab'),
this.element.nativeElement.getElementsByClassName('fab')[0]);
on ngOnInit gives the following result:
What am I doing wrong here? Every part of the code related to the problem is equal to the tutorial and it's a quite recent video...
I think the reason here is that those elements are not present while you asking for them with that line:
console.log(this.element.nativeElement.getElementsByClassName('fab'),
this.element.nativeElement.getElementsByClassName('fab')[0]);
There is simple example which shows where problem can be:
console.log(document.getElementsByClassName('fab'), document.getElementsByClassName('fab')[0]);
const el1 = document.createElement('div');
el1.setAttribute('class', 'fab');
const el2 = document.createElement('div');
el2.setAttribute('class', 'fab');
setTimeout(() => {
this.abc.nativeElement.appendChild(el1);
this.abc.nativeElement.appendChild(el2);
}, 2000);
Elements are added after 2 seconds and console log is same like yours, but when you click on HTMLCollection it will evaluate and shows you those elements - of course if you click after 2 seconds(when elements are present).
If those element are really present when you asking for them console log should look more like:
HTMLCollection(2) [div.fab, div.fab]
Also, note that this little i in Google Chrome console inform you that value is evaluted just now - at the moment when you click on it.

Polymer 2.0 not able to get child from id

I'm kind of new to Polymer and i'm having an issue lately. I create dynamically a certain amount of instances of a web-component of mine, and I'd like to be able to call a method on these instances from my parent-component but I can't figure out how to do it even with answers I found online.
Here's my parent method where I try to call the children method (the e.detail.id match the id of the specific instance of my children I'm trying to reach) :
childObj: function(e) {
var name = "selectObj"+e.detail.id;
this.$.name.hello();
},
And my child basic method :
hello: function() {
console.log("hello");
}
The ID that name gets exists well but still i get this error
TypeError: Polymer.dom(...).querySelector(...) is null
I also tried replacing this.$.name.hello() by this.$$('#selectObj'+e.detail.id) but still I get the same error.
Here's how I create my childrens elements :
newObj: function() {
var dynamicSelect = document.createElement("pbd-object-select");
dynamicSelect.num = this.nbObj;
var newId = "selectObj" + this.nbObj;
dynamicSelect.id = newId;
Polymer.dom(this.root).querySelector("#listeObjet").appendChild(dynamicSelect);
},
There are two issues with they way you are trying to query for that element. One of them is that by doing this:
this.$.name.hello();
You are basically looking for an element with the id "name", not one with the id equal to what you have in the variable name. Something like:
this.$[name].hello();
might work better in general, but it would still have some problems in your particular case. this.$ is just a "shortcut" to get elements by ID in an easy manner, but, it's just an object in which references to the elements that exist and have ids when the element is connected. Because of that it doesn't work with elements that are conditionally included (in dom-ifs for example), or that are dynamically generated, like in your case.
You can just use the getElementById method, like you would do in vanilla JS, just keeping in mind that you are querying in your element and not in document. So it would be something like:
this.shadowRoot.getElementById("selectObj"+e.detail.id).hello()

Templatizer - How to render multiple times same template, Polymer 2.x

In Polymer 1.x I was used to write a templatize code like this:
renderTemplate(query, properties) {
let element = this.shadowRoot.querySelector(query);
this.templatize(element);
var instance = this.stamp(properties);
return instance;
}
which worked well. But in Polymer 2.x there is a new error message A <template> can only be templatized once. Well it doesn't make sense, because I have 1 template which I want to redistribute multiple times with different properties.
I am giving here an example of how is my code
I have #template1 and #template2
I want to render #template1 then #template2 then #template1.
In steps how I render templates:
1) templatize #template1
2) stamp properties
3) templatize #template2
4) stamp properties
5 a) templatize #template1 => ERROR
5 b) skip templatize and stamp properties => #template2 is rendered....
How am i able to make this possible? calling stamp() after rendering #template2 will result in another #template2 render. I want #template1, but I can't templatize #template1 because it has been already templatized. And stamp is always "binded" to last templatized element.
Am I doing something wrong? I do really hate Polymer because of it's bad documentation and hard to google something usefull
I found a workaround which is propably not the best solution but it works. I tried to search in source code for some solutions but there wasn't anything usefull except the one property called __templatizeOwner. This property is set to all templatized elements. Removing this property from an element is the way.
renderTemplate(query, properties) {
let element = this.shadowRoot.querySelector(query);
if(element.__templatizeOwner) {
element.__templatizeOwner = null;
}
this.templatize(element);
var instance = this.stamp(properties);
return instance;
}
I am not sure what side effects this might have (more memory usage or something) but this is the only way I was able to find out.

Angular2 function call from html element with no load event (or similiar)

I am new to Angular and have run into a problem that seems to have a javascript work around but they aren't very elegant.
I have a model with an array property. I ngfor the list property to build some html selection options. This is all working nicely. The problem comes when I am trying to set default value...the html elements don't have a load event.
I tried numerous html elements and they don't appear to have a load event either but I certainly could be doing it wrong.
I have seen a solution to put javascript tag right after the html and I could do that but I was really looking for a more elegant way in Angular.
I saw this SO post and thought that was my answer but there is a warning given that I agree with and thus it doesn't appear to be a good solution.
Regardless I tried it just to see if it would work and I got:
Failed to execute 'setAttribute' on 'Element': '{{loadDefaults()}}' is not a valid attribute name
<span {{loadDefaults()}} ></span>
So how can I fire an AS2 function in the component to load the default values?
HTML (btw this is NOT a full page load so there is no body tag):
<tr>
<td *ngFor="let loc of locOptions;">
<span>{{loc.text}}</span>
<input type="radio" name="radiogroup" [value]="loc.value" (change)="onSelectionChange(loc.value)">
</td>
</tr>
Edit
I thought perhaps mistakenly that ngoninit would fire too soon...before the html elements are rendered.
So perhaps what is being suggested is that I add a boolean is default to the model and bind THAT as the element is rendered.
In your ngonit function set this.locOptions to your default values. The value can be changed later on in any function and the change will be reflected in the view. Hope this helps you.
You should use ngOnInit to init you data, and call retrieve your data from your component :
defaults : any;
ngOnInit {
this.defaults = loadDefaults();
}
loadDefaults() {
//get data
}
HTML :
<span>{{defaults}}</span>

How to query the Input field of a Paper Input element in dart

So, I'm trying to access the input field hidden deep within a paper input field. This is so that I can change the input type and so on. After inspecting the element, You can see that it has 2 shadow roots as explained in this blog. However, the method explained in that blog no longer works. I'm using dart version 1.5.3, polymer 0.12.0-dev.
I try to query the paper input like so:
querySelector('#paper-input-id').shadowRoot.querySelector('#input');
However, that returns null. This is because the shadowRoot property only returns the first shadow root. The input field is buried in the second shadow root. I guess what I am asking is if there is a generic way to select the nth-shadow root of an element?
This seems exactly how I did it in the unit test for <core-input>
var input = dom.document.querySelector("#changeAndInputEvent") as CoreInput;
var domInput = (input.shadowRoot.olderShadowRoot.querySelector('#input') as dom.InputElement);
what also should work is
var domInput = (dom.document.querySelector("#changeAndInputEvent /deep/ #input");
or
var domInput = (dom.document.querySelector("* /deep/ #changeAndInputEvent /deep/ #input");
when the paper-input itself is inside a shadow-dom
Instead of using shadowRoot and olderShadowRoot, which may change if for whatever reason paper-input decides to inherit something new that then inherits from core-input, try using the more generic shadowRoots map (note the 's'):
querySelector('#paper-input-id').shadowRoots['core-input'].querySelector('#input');