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

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.

Related

How to access the style attribute of Primeng table

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.

Navigating to a page in a custom event doesn't work properly

When I navigate to a page using this event:
this.events.subscribe('liveTrackingEvent', (time, unit) => {
console.log("event triggered");
this.searchForm.controls['unitID'].setValue(this.unitSelected.unit.name);
this.GetLiveData();
});
everything gets called, also the function GetLiveData(). (I didn't post this function's code because it's irelevant)
However when I look at the page, not 1 element is updating. So this line:
this.searchForm.controls['unitID'].setValue(this.unitSelected.unit.name);
doesn't update the searchform control, however when I call this line of code from the page itself without the event getting triggered on another page, it works smoothly and updates the searchform control.
(It's like I'm on a separate thread for some reason), I'm putting this between brackets because it's just a thought.
So my question is: How do I force this page to update itself also when the event is triggered?
Thanks in advance and if you guys need more code just ask, but this is the most relevant code because everything is working just not when it gets called inside the event.
By using page life cycle events instead of custom events from the ionic framework I managed to make this work and even have a cleaner code.
example:
1st page:
GoToLiveTracking(unitID){
this.navCtrl.push(MapPage, {redirected: true, unitID: unitID});
}
2nd page:
ionViewDidEnter(){
if(this.navParams.get('redirected')){
let unit_id = this.navParams.get('unitID');
this.unitSelected = this.completeService.GetUnitByID(unit_id);
this.searchForm.controls['unitID'].setValue(this.unitSelected.unit.name);
this.GetLiveData();
}
}
I could think of only 1 reason for this behavior. You are updating your form outside of Angular Zone. That’s why the changes are not getting detected.
To fix the issue, wrapped the call of last 2 lines of event into “this.ngZone.run(() => { ... })”.
e.g
this.events.subscribe('liveTrackingEvent', (time, unit) => {
console.log("event triggered");
this.ngZone.run(()=>{
this.searchForm.controls['unitID'].setValue(this.unitSelected.unit.name);
this.GetLiveData();
});
});

Polymer 1.x: iron-data-table does not load data nor header styles on first render when inside neon-animated-pages

The below screenshot shows how my iron-data-table element looks when it first loads. Notice the data is missing and the headers are not fully formatted (the width seems to be too small to show the column header labels).
However, if I enter a character in the filter fields or click one of the sort buttons, the iron-data-table seems to re-draw itself and it looks fine. The columns and headers render properly and the data populates the table as expected.
This problem started when I added some directories to my file structure nested my iron-data-table inside neon-animated-pages. I double checked and all my imports are loading correctly. But I suspect that, somehow, there is a slight delay in fetching the data and somehow the table might be trying to render before the data arrives and not refreshing after the data arrives.
So I tried to add the following function. But to no avail. There is no render() method for iron-data-table.
<iron-data-table id="grid" ...
....
attached: function() {
this.async(function() {
this.$$('#grid').render();
}.bind(this), 500);
},
What could be causing this behavior? And what should I try next?
Edit
This plunk demonstrates the desired iron-data-table behavior.
This plunk demonstrates my problem behavior. (Not finished yet. Currently in progress.)
The configuration is approximately as follows.
parent-el.html
<neon-animated-pages>
...
<container-el...>...</container-el>
</neon-animated-pages>
container-el.html
<child-el ...>...</child-el>
child-el.html
<iron-data-table ...></iron-data-table>
Edit 2
Based on #SauliTähkäpää's comment, I tried the following fix unsuccessfully.
parent-el.html
<neon-animated-pages id="animator" ...>
...
<container-el...>...</container-el>
</neon-animated-pages>
...
attached: function() {
this.async(function() {
this.$.animator.notifyResize();
}.bind(this), 50);
},
Not that familiar with neon-animated-pages but by looking at the docs, it should call notifyResize() on selected pages as long as they extend iron-resizable-behavior.
So I think your options are either to make sure <container-element> and other elements in the tree are extending iron-resizable-behavior OR override the resizerShouldNotify to notify the grid directly. See more here: https://elements.polymer-project.org/elements/neon-animation?active=neon-animated-pages#method-resizerShouldNotify
To explicate for anyone who follows this question later...
Per #SauliTähkäpää's accepted answer, I successfully added the following code to each element in the chain (i.e., beginning with the element containing neon-animated-pages and ending with the element containing iron-data-table — in this example, that would be parent-el, container-el, and child-el).
parent-el.html, container-el.html, child-el.html.
<link rel="import" href="path/to/bower_components/iron-resizable-behavior/iron-resizable-behavior.html">
...
behaviors: [
Polymer.IronResizableBehavior,
],

Take Photo in WinJS-WP8.1-App

I try to make a photo-app that can read Qr-Codes with the ZXing-Library.
Most parts work but now somehow my LowLagPhotoCapture doesn't return anything useful:
var photoProperties = MediaProperties.ImageEncodingProperties.createJpeg();
mediaCaptureMgr.prepareLowLagPhotoCaptureAsync(photoProperties)
.done(function (_lowLagPhotoCapture) {
lowLagPhotoCapture = _lowLagPhotoCapture;
lowLagPhotoCapture.captureAsync()
.done(function (capturedPhoto) {
...
The MediaCaptureMgr works, I see a preview of the cam on the screen. But now I need to make a photo. The usual PhotoCapture didn't work with JavaScript and so I found this solution.
Somehow the lowLagPhotoCapture.captureAsync() crashes saying that lowLagPhotoCapture is empty. lowLagPhotoCapture is defined outside of this class because I need it later. But even if I pass the variable directly to the new method it fails =/
Any ideas what might go wrong with this?
Edit:
Okay, after every Async-operation I had a following nameless function and one exitOnError-function that was calles every time. If I remove thatv exitOnError-function out of .done(complete, error), it exits in the same place. But if I set a breakpoint on .captureAsync it goes 1-2 steps further, creates an ImageStream and exits somewhere there. Why the different behaviour with and without the breakpoint?

html5 drag and drop files from desktop with knockout

I am trying to implement drag and drop files from desktop using knockout. The starting code is taken from html5rocks.
I tried to implement this using event binding, so my View looks something like this:
<div class="drop_zone" data-bind="event:{
dragover: function(data, e){ $root.dragover(e);},
drop: function(data, e){ $root.drop(e, $parent);},
dragenter: function(data, e){ $root.dragenter(e);},
dragleave: function(data, e){ $root.dragleave(e);}
}">Drop files here</div>
The $parent parameter was used in attempt to do something similar to my previous question, where parent was able to locate where exactly the element should be removed.
My ViewModel is an observableArray of observableArrays (many dropzones) and looks like this:
this.dropZones = ko.observableArray([{
'elements' : ko.observableArray([])
},{
'elements' : ko.observableArray([])
}]);
The full code can be found in jsFiddle, but the problem is that I can not properly add new files to the files element. Also I can not correctly highlight the element the person is dragEntering/Leaving.
I understand why I can not highlight the proper element (I just select every class, but I can not understand how to select the parent element), I am failing to understand why parent.elements.push(f.name); does not add the name of the file to the right parent.
Can anyone please tell me what is the problem and how can I fix it?
P.S. in jsFiddle I get the error:
TypeError: Cannot read property 'dataTransfer' of undefined
which tells me that I am passing wrong event, but the same code on my local server does not give me this problem. The error which I am getting on localhost is:
Uncaught TypeError: Cannot call method 'push' of undefined
which tells me that my idea of using parent was wrong.
1) { $root.drop(e, $data);} instead of { $root.drop(e, $parent);}
2) var files = e.dataTransfer.files; (without originalEvent)
Fiddle. (I've not fixed problem with css, do it youself :))
You should use $data instead of $parent because of elements is the property of each dropZone element. So, when you iterate with foreach: dropZones you have access to current element by $data, and you should send to $root.drop function current element (not parent) for get access to it elements array.
Update:
Solved CSS problem. (with help of $index() and jQuery .eq())
You could read about binding context (parent, data, index and etc.) here.