I want to navigate to a webpage url from the ionic html page. I have tried following :
This example
{{test.refWebsite}}
This example:
<ion-router-link href="{{test.refWebsite}}">{{test.refWebsite}}</ion-router-link>And finally this:
<a [routerLink]="{{test.refWebsite}}">{{test.refWebsite}}</a>
Ever example navigates to my 'page-not-found' route defined in the app.routng.module:
{ path: '**', redirectTo: 'page-not-found' }, So my question is how do I navigate to an external website form my ionic app html page?
Update: Following the Capacitor documentation I have implemented as follows:
import { Plugins } from '@capacitor/core'; const { Browser } = Plugins; async openBrowser(webpage){ console.log("home.page.ts: Opneing Web browser: " + webpage); await Browser.open({url: webpage}); } //HTML implementation
<p (click)="openBrowser(test.refWebsite)">Referral Center: <a> {{test.refWebsite}}</a></p> Console output shows a valid URL is been passed tot he function:
home.page.ts: Opneing Web browser: www.sheffieldchildrens.nhs.uk/sdgs/oncology-genetics
However I am still getting the 'page-not-found' opening, although the URL (webpage) is valid, any input appreciated as I can't see why this is happening.
ADDING COMPLETE CLASS FILE:
home.page.ts
mport { Component, ɵChangeDetectorStatus } from '@angular/core'; import { AlertController, ModalController } from '@ionic/angular'; import { Student, Test, StudentService } from '../services/student.service'; import { StudentModalPage } from '../student-modal/student-modal.page'; import {FormControl, ReactiveFormsModule } from '@angular/forms'; import { debounceTime} from "rxjs/operators"; import { serializeNodes } from '@angular/compiler/src/i18n/digest'; import { IonSlides, MenuController } from '@ionic/angular'; import { Storage} from '@ionic/storage'; import { CallNumber } from '@ionic-native/call-number/ngx'; import { Plugins } from '@capacitor/core'; import { stringify } from '@angular/compiler/src/util'; const { Browser } = Plugins; // import { Plugins } from '@capacitor/core'; // const { Storage } = Plugins; @Component({ selector: 'app-home', templateUrl: 'home.page.html', styleUrls: ['home.page.scss'], }) export class HomePage { //Firelds public students : Student[]; public tests : Test[]; public searchTerm : string; public searchControl : FormControl; public searching : any = false; public adminUser : any = false; public cacheData : Test[]; public referralPhoneNumber : string; constructor( private service : StudentService, private alertCtrl : AlertController, private modalCtrl : ModalController, private menu : MenuController, private storage : Storage, private callNumber : CallNumber ) { this.searchControl = new FormControl(); } ionViewDidEnter(){ this.menu.enable(true); //See if admin user //this.adminUser = Storage.get({key: 'adminUser'}); this.storage.get('adminUser').then((val) =>{ console.log("home.pg: value of admin user = ", val); this.adminUser = val; console.log("home.page: Is user admin user: " + this.adminUser); }); //this.storage.set('adminUser', true); } ngOnInit() { /** * Get data from the SQL DB and store in local array Test * This calls student.serce which in turn calls the GET API * Set up serach Form, debounce tme is time to wait * before before triggerng serah / observable */ this.searching = true; console.log("Home.page: ngOnOt- Gettnig all data..."); this.service.getAll().subscribe(response => { console.log("Home.ts: getAll call = " + response); //this.students = response; this.tests = response; this.searching = false; //Turn spinner off //Cache data // Storage.set }); // this.setFilteredTests(""); this.searchControl.valueChanges .pipe(debounceTime(700)) .subscribe(search=> { this.searching = false; this.setFilteredTests(search); }); } setFilteredTests(searchTerm : string){ /** * USer teh seah term form user input to filter * the test array * https://www.joshmorony.com/high-performance-list-filtering-in-ionic-2/ * Assign a lcoal var tp current tests array which we will use * to reasign tests if searh is null or empty. * This saves us making another tme wasting PAI get call */ console.log("Home.page.ts: 44 Ste filter serach bar called, serach = " + searchTerm); if (searchTerm != ""){ this.tests = this.tests.filter(test => { if (test.investigation.toLowerCase().indexOf(searchTerm.toLowerCase()) == -1){ console.log("Home.page.ts 73= Serach not found for " + searchTerm + " so searching alais"); return test.Alias.toLowerCase().indexOf(searchTerm.toLowerCase()) > -1; } console.log("home.oage: 78: Found " + searchTerm + " in test.investigation."); return test.investigation.toLowerCase().indexOf(searchTerm.toLowerCase()) > -1; }) }else{ console.log("Home.page.ts: Seathetrm is blank - " + searchTerm + "; so getting dtta with GET API"); this.service.getAll().subscribe(data => { this.tests = data; }) } } onSearchInput(){ /** * Turn on spinner when seraching * Set to false when loaing page and when serach observable triggers in onIt */ this.searching = true; } async openBrowser(webpage){ console.log("home.page.ts: Opneing Web browser: " + webpage); await Browser.open({url: webpage}); } removeTest(id : number){ console.log("Home.page.ts: Remove test id : " + id); if (this.adminUser){ this.alertCtrl .create({ header: 'Delete', message: 'are you sure you want to delete this test?', buttons : [ { text: 'Yes', handler: () => { this.service.remove(id).subscribe(() => { // Filter the tst array to all test.id's excpet one removed this.tests = this.tests.filter(std => std.id !== id); }); } }, { text: 'No'} ] }) .then(alertE1 => alertE1.present()); }//if this admin user else{ this.alertCtrl.create({ header: 'Delete', message: 'You must be an administrator to make these changes', buttons : [ { text: 'OK' } ] }) .then(alertE1 => alertE1.present()); } } callPhoneNumber(phoneNumber) : void{ //Usre clicked call number, https://ionicframework.com/docs/native/call-number let correctNumber = phoneNumber.replace(/\s/g,"");//remove whitespace console.log("home.page: call Nimber() " + correctNumber); this.callNumber.callNumber(phoneNumber, true) .then(res => console.log("Launched Dialer", res)) .catch(err => console.log("Error launching handler", err)); // this.callNumber.callNumber("18001010101", true) // .then(res => console.log('Launched dialer!', res)) // .catch(err => console.log('Error launching dialer', err)); } addStudent(){ /** * Call studentmodal page * Also when Add Student page is closed * we will capture what teh page sends back when navCtlr.dismiss(params) * is called, so we can upadte any new test additions to this page * The modal presnet teh Add Student page, .then() return inof sent back * from this page. */ console.log("Home.ts: Add test"); if (this.adminUser){ this.modalCtrl.create({ component: StudentModalPage }) .then(modal => { modal.present(); return modal.onDidDismiss(); }) .then(({ data, role}) => { if ( role === 'created'){ //add new test from Add Test page to test arrauy console.log("Home.page: 148- New test created : " + data + "- Adding to Tests Array view.") //this.students.push(data); this.tests.push(data); } }); }//if this admin user else{ this.alertCtrl.create({ header: 'Add', message: 'You must be an administrator to make these changes', buttons : [ { text: 'OK' } ] }) .then(alertE1 => alertE1.present()); } } updateStudent(test){ /* We need to pas the student object ot the * StidentModalPage with modalCtrl * And we also handle the retuned data from Student Modal Page */ console.log("Home.page.ts: upadte, passing to StudentModalPage student - " + test.investigation + " : id - " + test.id); if (this.adminUser){ this.modalCtrl.create({ component : StudentModalPage, //componentProps : {student : student} componentProps : {test : test} }) .then(modal => { modal.present(); //get returned moddel form Stdent Model page console.log("home.page.ts: 92: Getting return data form Stduent Modal page Uodate / PUT"); return modal.onDidDismiss(); }) .then(({ data, role}) => { //this.students = this.students.filter(std => { this.tests = this.tests.filter(std=> { console.log("Home.page.ts: 97: Retrining to home frm Student modal update / PUT with data studnet IFD to update list: " + data.id); if (data.id === std.id){ //return uodated tests array return data; } return std; }); }); } //if this admin user else{ this.alertCtrl.create({ header: 'Delete', message: 'You must be an administrator to make these changes', buttons : [ { text: 'OK' } ] }) .then(alertE1 => alertE1.present()); } }//upadtes test } HTML
<ion-header [translucent]="true"> <ion-toolbar color="primary"> <ion-buttons slot="start"> <ion-back-button defaultHref="app/categories">Menu</ion-back-button> </ion-buttons> <ion-buttons slot="end"> <ion-button color="primary" (click)="addStudent()"> Add New </ion-button> </ion-buttons> <ion-title> All tests </ion-title> </ion-toolbar> </ion-header> <ion-content ion-padding color="primary"> <ion-header collapse="condense"> <ion-toolbar> <ion-title size="large">User Manual Tests</ion-title> </ion-toolbar> </ion-header> <!--Serachbar--> <ion-searchbar [formControl]="searchControl" (ionChange)="onSearchInput()"> </ion-searchbar> <!--Spinner for serach box--> <div *ngIf="searching" class="spinner-container"> <ion-spinner></ion-spinner> </div> <!--<ion-list *ngFor="let student of students">--> <ion-list *ngFor="let test of tests" color="primary"> <ion-item-sliding> <ion-item > <ion-avatar slot="start"> <div class="avatar"> <!--{{student.name.substring(0,1).toUpperCase()}}--> {{test.investigation.substring(0,1).toUpperCase()}} </div> </ion-avatar> <ion-label> <!-- <h3 class="title">{{student.name}}</h3> <p class="subtext"> {{'From ' + student.address + ' Tel: ' + student.phone}} </p> --> <h3 class="title">{{test.investigation}}</h3> <p class="subtext">Speciman Type: {{test.SpecimanType}} <br> {{test.Comments}} <br>Container: {{test.container}} <br>Phone: {{test.phone}} <br>TAT: {{test.TAT}} <br>Phoning Criteria: {{test.phoneCriteria}} <br>Referred Tests (Y/N): {{test.referred}} </p> <div class = "subtext" *ngIf="test.referred == 'Y'"> <a (click)="openBrowser(test.refWebsite)">{{test.refWebsite}}</a> <a href="{{test.refWebsite}}">OPEN {{test.refWebsite}}</a> <p (click) = "callPhoneNumber(test.refNumber)"> Refferal Number: <a>{{test.refNumber}}</a></p> </div> </ion-label> </ion-item> <ion-item-options slide="end"> <ion-item-option color="danger" (click) = "removeTest(test.id)"> <ion-icon name="trash"></ion-icon> </ion-item-option> <ion-item-option color="success" (click)="updateStudent(test)"> Edit </ion-item-option> </ion-item-options> </ion-item-sliding> </ion-list> <!-- <div id="container"> <strong>Ready to create an app?</strong> <p>Start with Ionic <a target="_blank" rel="noopener noreferrer" href="https://ionicframework.com/docs/components">UI Components</a></p> </div> --> </ion-content>