Use ViewChild on Directive's Child


#1

Well,
I wonder if it’s possible to reference an element from a directive (i.e. ion-searchbar) from my Page.ts

I’ve tried to assign a variable to it and it’s not possible:

export class MyModal {
  @ViewChild('input') input;
  ...

  ionViewLoaded() {
    console.log(this.input)
    ...

with the variable on the template:

<ion-searchbar [(ngModel)]="query" (ionInput)="search($event)" #input>

but it shows that this.input is undefined

Studying the ion-searchbar code I see that it does reference its input element with #searchbarInput and tried to reference it with @ViewChild('searchbarInput') input; unsuccessfully too.

I have to master Angular 2 better, I know
Any thoughts please?


#2

searchbarInput is documented as private, so the framework doesn’t want you accessing it directly. Is there no way to achieve what you are really trying to do using public properties?


#3

I don’t know what is public on that directive, nor how to manipulate it correctly either.
I need the input element to pass it to google.maps.places.Autocomplete(input: HTMLInputElement)

I don’t think the API let me manipulate it as it seems:


#4

Yeah, that does seem like something impossible to do with the public API, so might have to go off reservation here. OTHER PEOPLE READING THIS THREAD: DON’T DO THIS SORT OF STUFF UNTIL YOU HAVE EXHAUSTED ALL OTHER OPTIONS.

<ion-searchbar #searchbar></ion-searchbar>
export class MyPage {
  @ViewChild('searchbar') searchbar:Searchbar;

  ionViewLoaded():void {
    let elem = this.searchbar._searchbarInput.nativeElement;
    google.maps.places.Autocomplete(elem);
  }
}

If you’re still getting undefined, there is some ancillary problem, because that works for me on a scratch project.


#5

I get a TypeScript error :sweat:

Error TS2341: Property '_searchbarInput' is private
and only accessible within class 'Searchbar'.

Could you try to implement it in a Modal page please?
I’m getting the undefined there, and now searching for some method on the ViewController to manipulate childs!


#6

Unfortunately, the Ionic build defaults eat that error, so I didn’t notice it.

Works fine.

@Component({
  template: `
  <ion-content padding>
    <h2>I'm a modal!</h2>
    <ion-searchbar #searchbar></ion-searchbar>
    <button (click)="close()">Close</button>
  </ion-content>`
})
export class MyModal {
  // "any" subverts the type-checking allowing us to access the private member
  @ViewChild('searchbar') searchbar:any;
  
  constructor(
    private viewCtrl: ViewController) {}

  ionViewLoaded() {
    console.log(this.searchbar._searchbarInput.nativeElement);
  }
  
  close() {
    this.viewCtrl.dismiss();
  }
}
  popModal():void {
    let modal = Modal.create(MyModal);
    this._navController.present(modal);
  }


#7

Dang, could be my transpiler on strict mode or something?
because it’s failing silently when I try to console.log the nativeElement…

console.log(this.searchbar);

Pasting your modal next to mine doesn’t work either, and I still get undefined for both.

I have many cordova plugins and stuff on my app, and my packages are:

"dependencies": {
    "@angular/common": "^2.0.0-rc.1",
    "@angular/compiler": "^2.0.0-rc.1",
    "@angular/core": "^2.0.0-rc.1",
    "@angular/http": "^2.0.0-rc.1",
    "@angular/platform-browser": "^2.0.0-rc.1",
    "@angular/platform-browser-dynamic": "^2.0.0-rc.1",
    "@angular/router": "^2.0.0-rc.1",
    "es6-shim": "^0.35.0",
    "ionic-angular": "2.0.0-beta.9",
    "ionic-native": "1.2.4",
    "ionicons": "3.0.0",
    "reflect-metadata": "^0.1.3",
    "rxjs": "5.0.0-beta.6",
    "zone.js": "^0.6.12"
  },
  "devDependencies": {
    "del": "2.2.0",
    "gulp": "3.9.1",
    "gulp-watch": "4.3.5",
    "ionic-gulp-browserify-typescript": "^1.1.0",
    "ionic-gulp-fonts-copy": "^1.0.0",
    "ionic-gulp-html-copy": "^1.0.0",
    "ionic-gulp-sass-build": "^1.0.0",
    "ionic-gulp-scripts-copy": "^2.0.0",
    "run-sequence": "1.1.5"
  }

I executed ionic state restore with no luck :worried:


#8

Your compiler options on tsconfig.json are like these?

  "compilerOptions": {
    "target": "es5",
    "module": "commonjs",
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true
  }

#9

Did not change anything from the stock Ionic starter. Yes, looks identical. I am running in Chromium on Debian sid, if that matters.


#10

I’m running Chrome on Ubuntu 16.04
ionic info:

Cordova CLI: 6.1.1
Ionic Framework Version: 2.0.0-beta.9
Ionic CLI Version: 2.0.0-beta.30
Ionic App Lib Version: 2.0.0-beta.16
OS: Distributor ID:     Ubuntu Description:     Ubuntu 16.04 LTS 
Node Version: v4.2.6

Maybe my node version?


#11

I have a hard time thinking node version could have anything to do with this, but I am running 6.2.1.


#12

Well, I’ve seen build issues with Node 6, and the solution was to downgrade to 5.7…
Maybe the transpiled code can differ with some base libraries versions :disappointed:


#13

Can you try it from my end and paste my code into a newly minted project? I used the tabs starter and put that popModal() function in the home page with a button to trigger it like this:

  <button (click)="popModal()">pop modal</button>

If that doesn’t work, then it is an environmental thing. If it does, then it’s something else unusual about the rest of your project.


#14

Nice idea,
but in fact, I updated node

sudo npm cache clean -f
sudo npm install -g n
sudo n stable

cleaned up the node_modules folder and installed again:

sudo rm -Rf node_modules/
sudo npm install

and now I get the INPUT element :smile:

Node Version: v6.2.2

Thank you very very much @rapropos!!
Now I’m getting issues with the output of the build process hehehe,
but it runs on my phone, awesome!
now have to figure out if the Google Places autocompleter can work with ion-searchbar or not :wink:

Thanks again!!


#15

Glad it’s working. At some point, you might want to look at nvm. It allows you to install multiple node versions and nothing has to be done as root.


#16

Nice one, thank you!


#17

After a rebuild of the project, I got undefined again…

I’m switching to a safer path:

<HTMLInputElement>document.getElementsByClassName("searchbar-input")[0];

then I can use it into google.maps.places.Autocomplete(elem) :slight_smile:


#18

I could swear using

let input = this.searchBar.inputElement;
let autocomplete = new google.maps.places.Autocomplete(input, {});

was working before I upgraded to the latest Beta version of Ionic.

Let me try your approach ans see how that goes.


#19

It is working fine using

this.searchbar._searchbarInput.nativeElement

and

<HTMLInputElement>document.getElementsByClassName("searchbar-input")[0];

Thanks or giving me the options :slight_smile:


#20

You’re welcome!
odd enough I get undefined on the #searchbar viewchild :frowning:
I opened a request to the SearchBar API to let us access the Input Element but Angular already allowed us to get it! details here: https://github.com/driftyco/ionic/issues/7223