Ionic 4 with Angular how to set dynamic HTML dir a

2020-07-25 08:43发布

问题:

I want to detect the translation file of the user and based on it, to get the required direction. For example, HE will get RTL, EN will get LTR.

However I don't find a way to implement the data in the <html dir=""> tag

This is the index.html file:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Ionic App</title>
  <meta name="viewport" content="viewport-fit=cover, width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
  <meta name="format-detection" content="telephone=no">
  <meta name="msapplication-tap-highlight" content="no">

  <link rel="icon" type="image/x-icon" href="assets/icon/favicon.ico">
  <link rel="manifest" href="manifest.json">
  <meta name="theme-color" content="#4e8ef7">

  <!-- add to homescreen for ios -->
  <meta name="apple-mobile-web-app-capable" content="yes">
  <meta name="apple-mobile-web-app-status-bar-style" content="black">

  <!-- cordova.js required for cordova apps (remove if not needed) -->
  <script src="cordova.js"></script>

  <!-- un-comment this code to enable service worker
  <script>
    if ('serviceWorker' in navigator) {
      navigator.serviceWorker.register('service-worker.js')
        .then(() => console.log('service worker installed'))
        .catch(err => console.error('Error', err));
    }
  </script>-->

  <link href="build/main.css" rel="stylesheet">

</head>
<body>

  <!-- Ionic's root component and where the app will load -->
  <ion-app></ion-app>

  <!-- The polyfills js is generated during the build process -->
  <script src="build/polyfills.js"></script>

  <!-- The vendor js is generated during the build process
       It contains all of the dependencies in node_modules -->
  <script src="build/vendor.js"></script>

  <!-- The main bundle js is generated during the build process -->
  <script src="build/main.js"></script>

</body>
</html>

And this is the app.component.ts

import { Component, ViewChild } from '@angular/core';
import { SplashScreen } from '@ionic-native/splash-screen';
import { StatusBar } from '@ionic-native/status-bar';
import { TranslateService } from '@ngx-translate/core';
import { Config, Nav, Platform } from 'ionic-angular';
import { Title } from "@angular/platform-browser";

import { FirstRunPage } from '../pages';
import { Settings } from '../providers';

@Component({
  templateUrl: "app.component.html"
})
export class MyApp {

  rootPage = FirstRunPage;

  @ViewChild(Nav) nav: Nav;

  pages: any[] = [
    { title: 'Tutorial', component: 'TutorialPage' },
    { title: 'Welcome', component: 'WelcomePage' },
    { title: 'Tabs', component: 'TabsPage' },
    { title: 'Cards', component: 'CardsPage' },
    { title: 'Content', component: 'ContentPage' },
    { title: 'Login', component: 'LoginPage' },
    { title: 'Signup', component: 'SignupPage' },
    { title: 'Master Detail', component: 'ListMasterPage' },
    { title: 'Menu', component: 'MenuPage' },
    { title: 'Settings', component: 'SettingsPage' },
    { title: 'Search', component: 'SearchPage' }
  ]

  constructor(private titleService:Title, private translate: TranslateService, platform: Platform, settings: Settings, private config: Config, private statusBar: StatusBar, private splashScreen: SplashScreen) {
    this.titleService.setTitle("Some title");
    platform.ready().then(() => {
      // Okay, so the platform is ready and our plugins are available.
      // Here you can do any higher level native things you might need.
      this.statusBar.styleDefault();
      this.splashScreen.hide();
    });
    this.initTranslate();
  }

  initTranslate() {
    // Set the default language for translation strings, and the current language.
    this.translate.setDefaultLang('en');
    this.translate.use(this.translate.getBrowserLang() || 'en');

    this.translate.get(['BACK_BUTTON_TEXT']).subscribe(values => {
      this.config.set('ios', 'backButtonText', values.BACK_BUTTON_TEXT);
    });
  }

  openPage(page) {
    // Reset the content nav to have just this page
    // we wouldn't want the back button to show in this scenario
    this.nav.setRoot(page.component);
  }
}

As you can see I don't have "scope" in the index.html file, only under the router outlet. How can I make custom changes in the index.html page?

回答1:

You cannot and should not try to put the html tags into angular components, at best it will cause trouble.

You would have to grab the instance of the browser document object by injecting it like this, e.g. in your app component:

https://angular.io/api/common/DOCUMENT

And set the dir attribute:

https://developer.mozilla.org/en-US/docs/Web/API/Document

import { Component, OnInit, Inject } from '@angular/core';
import { DOCUMENT } from '@angular/common';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent implements OnInit {

  constructor(@Inject(DOCUMENT) private doc) {}

  setDir(dir: string) {
    this.doc.dir = dir;
  }

  ngOnInit() {
    this.setDir('rtl')
  }
}

Probably this is best put into a separate service so you can clearly define how to interact with the document

Document Service

import { Injectable, Inject } from '@angular/core';
import {DOCUMENT} from '@angular/common';

type ReadingDirection = 'ltr' | 'rtl';

@Injectable({ providedIn: 'root' })
export class DocumentService {

  constructor(@Inject(DOCUMENT) private doc) {}

  public setReadingDirection(dir: ReadingDirection) {
    this.doc.dir = dir;
  }
}

App Component

import { Component,OnInit } from '@angular/core';
import { DocumentService } from './document.service';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  implements OnInit {
  name = 'Angular';

  constructor(private documentService: DocumentService) {}

  ngOnInit() {
    this.documentService.setReadingDirection('rtl')
  }

}

Demo:

https://stackblitz.com/edit/angular-p8riqb