skip to Main Content

I want to include the Telegram login widget in my Angular application. For this, you have to include the following script:

<script async src="https://telegram.org/js/telegram-widget.js?5"
  data-telegram-login="bot_name" data-size="large"
  data-auth-url="https://myurl.example/api/telegram"
  data-request-access="write"></script>

Embedding scripts in Angular templates is not allowed, it will just be removed. (However, it is possible to include a script tag via this hack.)

Is there a non-hacky way of including this widget?

2

Answers


  1. Chosen as BEST ANSWER

    I created the following component for the Telegram login widget:

    The component creates the script tag dynamically and adds the callback function loginViaTelegram(user):

    @Component({
      selector: 'app-telegram-login-widget',
      template: `    
    <div #script style.display="none">
      <ng-content></ng-content>
    </div>`,
      styleUrls: ['./telegram-login-widget.component.css']
    })
    export class TelegramLoginWidgetComponent implements AfterViewInit {
    
      @ViewChild('script', {static: true}) script: ElementRef;
    
      convertToScript() {
        const element = this.script.nativeElement;
        const script = document.createElement('script');
        script.src = 'https://telegram.org/js/telegram-widget.js?5';
        script.setAttribute('data-telegram-login', environment.telegramBotName);
        script.setAttribute('data-size', 'large');
        // Callback function in global scope
        script.setAttribute('data-onauth', 'loginViaTelegram(user)');
        script.setAttribute('data-request-access', 'write');
        element.parentElement.replaceChild(script, element);
      }
    
      ngAfterViewInit() {
        this.convertToScript();
      }
    
    }
    

    I added the callback function loginViaTelegram to the window object (global space) in a dedicated service:

    @Injectable({
      providedIn: 'root'
    })
    export class TelegramLoginService {    
      init() {
        window['loginViaTelegram'] = loginData => this.loginViaTelegram(loginData);
      }
    
      private loginViaTelegram(loginData: TelegramLoginData) {
        // If the login should trigger view changes, run it within the NgZone.
        this.ngZone.run(() => process(loginRequest));
      }
    }
    

  2. Not rendering script tags in template code is indeed a design choice from Angular team.

    The way to do it is thus:

    1. Add your scripts to index.html – only relevant if it makes sense to load the script globally.
    2. Or Add your script programmatically. The post you refer to can be a solution, but brings in additional complication because it takes the input data from template code. A shorter solution is given here, when you’re happy with inputing the parameters from the code-side (and the full issue is instructive too): Github issue #4903. Warning though: adding to the head is not suitable unless you remove it in OnDestroy. Prefer adding in the right DOM element of your component.
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search