I have an image element that I am trying to use ViewChild with:
<img class="postimage" #imagey [src]="">
My controller is this:
import { Component, ViewChild, ElementRef, Renderer } from '#angular/core';
import { IonicPage, NavController, NavParams } from 'ionic-angular';
/**
* Generated class for the PostpagePage page.
*
* See http://ionicframework.com/docs/components/#navigation for more info
* on Ionic pages and navigation.
*/
#IonicPage()
#Component({
selector: 'page-postpage',
templateUrl: 'postpage.html',
})
export class PostpagePage {
#ViewChild('imagey') image:ElementRef;
imageHolder;
constructor(public myrenderer: Renderer, public navCtrl: NavController, public navParams: NavParams) {
}
ionViewDidLoad() {
this.imageHolder = this.navParams.get("path");
this.myrenderer.setElementAttribute(this.image.nativeElement, 'src', this.imageHolder);
console.log(JSON.stringify(this.image));
}
pushPage(){
// push another page on to the navigation stack
// causing the nav controller to transition to the new page
// optional data can also be passed to the pushed page.
//this.navCtrl.push(SignUpPage);
}
}
The result of the console message in ionViewDidLoad is:
{"nativeElement":{}}
It doesn't seem to be returning an element.
I had to remove the ion-item that was containing the image - then it worked. It is actually still loggin an empty object to the console.
Related
I have a component named RedirectUserToMobileAppComponent , I want to share a boolean property from it named enableLoginForm with app.component.
When I execute, I get this error :
enableLoginForm is undefined property on ngAfterViewInit in app.component
this is RedirectUserToMobileAppComponent component:
import {
Component,
ComponentFactoryResolver,
ComponentRef,
Inject,
Input,
OnInit,
Output,
ViewChild,
ViewContainerRef,
} from '#angular/core';
import { Observable, Subscription } from 'rxjs';
import { filter, map, pluck, tap } from 'rxjs/operators';
import { ActivatedRoute, Router } from '#angular/router';
import { MAT_DIALOG_SCROLL_STRATEGY_FACTORY } from '#angular/material/dialog';
#Component({
selector: 'redirect-user-to-mobile-app',
templateUrl: './redirect-user-to-mobile-app.component.html',
styleUrls: ['./redirect-user-to-mobile-app.component.sass'],
})
export class RedirectUserToMobileAppComponent implements OnInit {
constructor(
) {}
enableLoginForm = false;
ngOnInit(): void {}
OnLogin(): void {
this.enableLoginForm = true;
this.router.navigate(['../login']);
}
}
and this is app.component:
import {
Component,
HostListener,
OnDestroy,
OnInit,
ViewChild,
AfterViewInit,
} from '#angular/core';
import { MatIconRegistry } from '#angular/material/icon';
import { DomSanitizer } from '#angular/platform-browser';
import { FirebaseService } from './services/firebase/firebase.service';
import {
SnakeMessage,
SnakeMessageService,
} from './services/snakeMessage/snakeMessage.service';
import { MatSnackBar } from '#angular/material/snack-bar';
import { Subscription } from 'rxjs';
import { StorageService } from './services/storage/storage.service';
import { AuthService } from './services/auth/auth.service';
import { RedirectUserToMobileAppComponent } from './redirect-user-to-mobile-app/redirect-user-to-mobile-app.component';
#Component({
selector: 'app-component',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss'],
})
export class AppComponent implements OnInit, OnDestroy, AfterViewInit {
favIcon: HTMLLinkElement = document.querySelector('#appIcon');
private snakeMessageSub: Subscription;
isLoading = true;
isLogged: boolean;
#ViewChild(RedirectUserToMobileAppComponent)
redirectComponent!: RedirectUserToMobileAppComponent;
constructor(
private matIconRegistry: MatIconRegistry,
private firebaseService: FirebaseService,
private snakeMessageService: SnakeMessageService,
private _snackBar: MatSnackBar,
private storageService: StorageService,
private domSanitizer: DomSanitizer,
private authService: AuthService
) {
this.registerCustomIcons();
this.storageService.initDB();
this.storageService.onLoaded$.subscribe((loaded) => {
if (loaded) {
this.isLoading = false;
}
});
this.isLogged = this.authService.isLoggedIn;
}
ngAfterViewInit() {
if (this.redirectComponent.enableLoginForm) {
this._is = this.redirectComponent.enableLoginForm;
}
}
ngOnInit(): void {
this.snakeMessageSub = this.snakeMessageService.messageSub.subscribe(
(snakeMessage: SnakeMessage) => {
this._snackBar.open(snakeMessage.message, snakeMessage.action, {
duration: 3000,
horizontalPosition: 'center',
verticalPosition: 'top',
});
}
);
}
this is my app.component.html
<ng-container *ngIf="!isLoading">
<ng-container *ngIf="isMobileDevice() && !isLogged">
<redirect-user-to-mobile-app> </redirect-user-to-mobile-app>
<router-outlet
*ngIf="enableLoginForm"
></router-outlet>
</ng-container>
<router-outlet *ngIf="!isMobileDevice()"></router-outlet>
This is how you use ViewChild:
#ViewChild('templateId', { static: false }) redirectComponent: RedirectUserToMobileAppComponent;
You should have the templateId set in the template part :
<redirect-user-to-mobile-app #templateId> ... </redirect-user-to-mobile-app>
EDIT: Though I agree with skyBlue, you should use a service to shared data between components
ViewChild returns a reference to the HTML element.
I will quote from angular.io:
Property decorator that configures a view query. The change detector looks for the first element or the directive matching the selector in the view DOM. If the view DOM changes, and a new child matches the selector, the property is updated.
So you cant access it's controller variables with ViewChild.
My suggestion for you is to use a service for passing data.
I have changed the method, I have used #Output() component and it works fine:
this is RedirectUserToMobileAppComponent component after changing the method :
import {
Component,
ComponentFactoryResolver,
ComponentRef,
Inject,
Input,
OnChanges,
OnInit,
Output,
SimpleChanges,
ViewChild,
ViewContainerRef,
EventEmitter,
} from '#angular/core';
import { Observable, Subscription } from 'rxjs';
import { filter, map, pluck, tap } from 'rxjs/operators';
import { ActivatedRoute, Router } from '#angular/router';
import { MAT_DIALOG_SCROLL_STRATEGY_FACTORY } from '#angular/material/dialog';
#Component({
selector: 'yobi-redirect-user-to-mobile-app',
templateUrl: './redirect-user-to-mobile-app.component.html',
styleUrls: ['./redirect-user-to-mobile-app.component.sass'],
})
export class RedirectUserToMobileAppComponent implements OnInit {
constructor(
private router: Router,
private componentFactoryResolver: ComponentFactoryResolver
) {}
#Output() _enableLoginForm: EventEmitter<boolean> = new EventEmitter();
variable: any;
login: boolean;
enableLoginForm = false;
enableSignupForm = false;
ngOnInit(): void {}
sendDataToParent() {
this.enableLoginForm = true;
this._enableLoginForm.emit(this.enableLoginForm);
console.log(this.enableLoginForm + ' From redirect ');
}
I added this to RedirectUserToMobileAppComponent.html:
<a class="login-text" (click)="sendDataToParent()">
Login
</a>
I added this code to app.component :
receiveChildData($event) {
this.enableLoginForm = $event;
}
I added this code to the app.component.html :
<redirect-user-to-mobile-app
(_enableLoginForm)="receiveChildData($event)"
>
</redirect-user-to-mobile-app>
list.component, which has an input variable tasks and listtype, which can be upcoming or completed. The #Output(s) are used if the task is checked (to become completed) and tasksChange, to change a task:
import {Component, EventEmitter, Input, Output} from '#angular/core';
import {Map, List} from 'immutable';
#Component({
selector: 'app-task-list',
templateUrl: 'task-list.component.html'
})
export class TaskListComponent {
#Input() tasks: string[] = [];
#Input() listType: 'upcoming' | 'completed' = 'upcoming';
#Output() itemChecked: EventEmitter<boolean> = new EventEmitter();
#Output() tasksChange: EventEmitter<string[]> = new EventEmitter();
constructor() { }
/**
* Is called when an item from the list is checked.
* #param selected---Value which indicates if the item is selected or deselected.
*/
onItemCheck(selected: boolean) {
this.itemChecked.emit(selected);
}
/**
* Is called when task list is changed.
* #param changedTasks---Changed task list value, which should be sent to the parent component.
*/
onTasksChanged(changedTasks: string[]) {
this.tasksChange.emit(changedTasks);
}
}
Now I wanted to display upcoming tasks with my upcoming-tasks.component, which has 3 mock tasks:
import { Component, OnInit } from '#angular/core';
import {TaskListComponent} from "../task-list/task-list.component";
#Component({
selector: 'app-upcoming-tasks',
templateUrl: './upcoming-tasks.component.html',
styleUrls: ['./upcoming-tasks.component.css']
})
export class UpcomingTasksComponent extends TaskListComponent {
upcomingTasks: string[] = ['bla', 'blub', 'bap'];
constructor() {
super();
}
ngOnInit(): void {
}
}
and the HTML of the upcoming-tasks.html:
<h1>Upcoming Tasks</h1>
<app-task-list [(tasks)]="upcomingTasks" [listType]="'upcoming'" (itemChecked)="onItemCheck($event)"></app-task-list>
So what am I missing to get these tasks on my UI?
few weeks ago I had a problem with the Google maps ionic native module, and I made a question (not solved).
Now I'm testing in a blank page and the map is shown, but it looks like:
This is my xml file, where I have the div that will contain the Map.
<ion-header>
<ion-navbar>
<ion-title>maptest</ion-title>
</ion-navbar>
</ion-header>
<ion-content style="background: pink;">
<div #map id="map" style="height: 80%;"></div>
</ion-content>
And here we have the ts file. Here I create the Map using ViewChild
import { Component, ViewChild, ElementRef } from '#angular/core';
import { IonicPage, NavController, NavParams } from 'ionic-angular';
import {
GoogleMaps,
GoogleMap,
CameraPosition,
LatLng,
GoogleMapsEvent,
GoogleMapOptions
} from '#ionic-native/google-maps';
/**
* Generated class for the MaptestPage page.
*
* See http://ionicframework.com/docs/components/#navigation for more info
* on Ionic pages and navigation.
*/
#IonicPage()
#Component({
selector: 'page-maptest',
templateUrl: 'maptest.html',
})
export class MaptestPage {
#ViewChild('map') mapElement: ElementRef;
map: GoogleMap;
constructor(public navCtrl: NavController, public navParams: NavParams, private _googleMaps: GoogleMaps) {
}
ngAfterViewInit() {
console.log('ngAfterViewInit');
this.initMap();
}
initMap() {
let element = this.mapElement.nativeElement;
this.map = GoogleMaps.create(element, {});//this._googleMaps.create(element);
// Wait the MAP_READY before using any methods.
this.map.one(GoogleMapsEvent.MAP_READY).then(() => {
console.log('Map is ready!');
}).catch( err =>{
console.error("Error maperino --> "+err);
});
}
moveCamera(location: LatLng) {
let options = {
target: location,
zoom: 18,
tilt: 30
}
this.map.moveCamera(options);
}
}
I don't know what I'm doing wrong :(
Since you can see the google logo, your code is fine.
The problem is your api key.
You need to try to regenerate the API key, and reinstall it.
Make sure you enable the google maps android api v2 and the google maps sdk for ios before generating the api keys.
https://github.com/mapsplugin/cordova-plugin-googlemaps-doc/blob/master/v1.4.0/TroubleShooting/Blank-Map/README.md
Even you tried the steps, and but you still get the gray map, contact to me directly. I will check it.
Its an answer, because I don't have reputation to add a comment.
Try add the Platform provider and then use platform ready inside the constructor to initialize your map.
contructor(public navCtrl: NavController,
public navParams: NavParams,
private _googleMaps: GoogleMaps,
private _platform: Platform){
this.platform.ready().then(() => {
this.initMap();
});
}
EDIT: It may be zoom too, try zoom out
EDIT2: Take a look at this slide about ionic and google-maps native
https://docs.google.com/presentation/d/1zlkmoSY4AzDJc_P4IqWLnzct41IqHyzGkLeyhlAxMDE/edit#slide=id.g292c767148_0_47
I'm working on an Ionic 2 project and I'm using a component called "offre".
I have got a problem running this component. It works correctly in the home page but not in the views (check this picture to see the error)
The data from firebase shown correctly in home.html but not in the other views!
Any suggestions?
Offre.ts code:
import { Component } from '#angular/core';
import { AngularFireDatabase, FirebaseListObservable } from "angularfire2/database";
import { IonicPage, NavController, NavParams} from 'ionic-angular';
import { NativeStorage } from '#ionic-native/native-storage';
#Component({
selector: 'offre',
templateUrl: 'offre.html'
})
export class OffreComponent {
text: string;
datas: FirebaseListObservable<any>;
user : any ;
constructor(public navCtrl: NavController, public db: AngularFireDatabase, public nativeStorage: NativeStorage) {
this.datas=db.list('/posts');
console.log('Hello OffreComponent Component');
}
Dear Stackoverflow community,
I have a problem with the angular2 Dialog, befor i give you the error here is a snipet of my Code(i have exluced a lot, but i think they might not be important here)
signup.component.ts file:
import {Component, OnInit, NgZone, SimpleChanges} from '#angular/core';
import {MdDialog} from '#angular/material';
import template from './signup.component.html';
#Component({
selector: 'signup',
template
})
export class SignupComponent implements OnInit {
constructor(private router: Router, private zone: NgZone, private formBuilder: FormBuilder, public dialog: MdDialog) {
}
openDialog() {
this.dialog.open(DialogOverviewExampleDialog);
}
#Component({
selector: 'dialog-overview-example-dialog',
templateUrl: './dialog.html',
})
export class DialogOverviewExampleDialog {}
signup.component.html file:
<h3 flex>Just<a (click)="openDialog()">Click here</a></h3>
and the dialog.html:
<p>pls work</p>
i get this error on the console in Chrome:
No component factory found for DialogOverviewExampleDialog
The DialogOverviewExampleDialog component must be declared in the entryComponents field of your NgModule. Otherwise, the angular compiler doesn't know that this component is displayed somewhere (since its selector isn't used in any template), and it's thus not compiled.