Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

tinymce not added to window if only tinymce is imported [TinyMCE+Webpack+Angular2] #3396

Closed
bjohnson-va opened this issue Dec 14, 2016 · 6 comments

Comments

@bjohnson-va
Copy link

bjohnson-va commented Dec 14, 2016

(See: #2836)

I'm trying to make an Angular2 component for a TinyMCE editor in my project. Here's my current setup.

package.json

{
  "name": "partner-center",
  "version": "0.0.0",
  "engines": {
    "node": ">=5.10",
    "npm": ">3.0"
  },
  "scripts": {
    "start": "webpack-dev-server --inline --progress --port 4000",
    "postinstall": "typings install",
    "lint": "tslint \"src/**/*.ts\"",
    "test": "karma start --single-run",
    "pree2e": "webdriver-manager update",
    "e2e": "protractor",
    "serve:hmr": "webpack-dev-server --progress --profile --colors --watch --display-error-details --display-cached --content-base --inline --hot",
    "build": "webpack --progress"
  },
  "private": true,
  "dependencies": {
    "@angular/common": "^2.0.0",
    "@angular/compiler": "^2.0.0",
    "@angular/core": "^2.0.0",
    "@angular/forms": "^2.2.3",
    "@angular/http": "^2.0.0",
    "@angular/material": "^2.0.0-alpha.10",
    "@angular/platform-browser": "^2.0.0",
    "@angular/platform-browser-dynamic": "^2.0.0",
    "@angular/router": "3.1.0",
    "@angular2-material/card": "^2.0.0-alpha.8-2",
    "@types/lodash": "^4.14.41",
    "core-js": "^2.4.0",
    "es6-shim": "^0.35.0",
    "exports-loader": "^0.6.3",
    "hammerjs": "^2.0.8",
    "highcharts": "4.2.5",
    "imports-loader": "^0.7.0",
    "intl": "^1.2.5",
    "jquery": "^3.1.0",
    "lodash": "^4.17.2",
    "moment": "^2.13.0",
    "reflect-metadata": "0.1.3",
    "rxjs": "5.0.0-beta.12",
    "systemjs": "0.19.26",
    "tether": "^1.3.4",
    "tinymce": "^4.5.1",
    "zone.js": "^0.6.12"
  },
  "devDependencies": {
    "angular2-template-loader": "^0.6.0",
    "css-loader": "^0.23.1",
    "file-loader": "^0.9.0",
    "html-webpack-plugin": "^2.22.0",
    "jasmine-core": "^2.4.1",
    "jasmine-spec-reporter": "^2.4.0",
    "karma": "^0.13.15",
    "karma-chrome-launcher": "^0.2.3",
    "karma-jasmine": "^0.3.8",
    "karma-phantomjs-launcher": "1.0.1",
    "karma-sourcemap-loader": "~0.3.7",
    "karma-teamcity-reporter": "1.0.0",
    "karma-webpack": "^1.7.0",
    "node-sass": "^3.8.0",
    "protractor": "^3.3.0",
    "raw-loader": "^0.5.1",
    "sass-loader": "^4.0.0",
    "style-loader": "^0.13.1",
    "ts-loader": "^0.8.2",
    "ts-node": "^0.5.5",
    "tslint": "^3.6.0",
    "typescript": "^2.0.00",
    "typings": "^0.8.1",
    "webpack": "^1.13.1",
    "webpack-dev-server": "^1.14.1"
  }
}

webpack.config.js

var webpack = require('webpack');

module.exports = {

  entry: './src/main.ts',
  output: {
    path: '../src/static/app',
    filename: 'app.bundle.js'
  },
  module: {
    loaders: [
      {test: require.resolve('tinymce/tinymce'),
       loaders: ['imports?this=>window', 'exports?window.tinymce']},
      {test: /\.ts$/, loader: 'ts!angular2-template'},
      {test: /\.html$/, loader: 'raw'},
      {test: /\.css$/, loader: 'raw'},
      {test: /\.scss$/, loader: 'raw!sass'},
      {test: /\.(eot|ttf|svg|gif|png|woff)$/, loader: "file-loader"}
    ]
  },
  resolve: {
    extensions: ['', '.js', '.ts', '.html', '.css', 'scss']
  },
  plugins: [
    new webpack.DefinePlugin({
      app: {
        environment: JSON.stringify(process.env.APP_ENVIRONMENT || 'development')
      }
    })
  ],
  devServer: {
    historyApiFallback: true
  }
};

html-editor.component.ts

import {
  Component,
  OnDestroy,
  AfterViewInit,
  EventEmitter,
  Input,
  Output,
} from '@angular/core';
require("jquery");
import tinymce from 'tinymce/tinymce'

require.context(
  '!file?name=[path][name].[ext]&context=node_modules/tinymce!tinymce/skins',
  true,
  /.*/
);

@Component({
  selector: 'html-editor',
  template: `
<textarea id="{{elementId}}"></textarea>
`})
export class HtmlEditorComponent implements AfterViewInit, OnDestroy {
  @Input() elementId: string;
  @Output() onEditorKeyup = new EventEmitter<any>();

  editor;

  ngAfterViewInit() {
    window['tinymce'].init({
      selector: '#' + this.elementId,
      menubar: 'format',
      toolbar: false,
      setup: editor => {
        this.editor = editor;
        editor.on('keyup', () => {
          const content = editor.getContent();
          this.onEditorKeyup.emit(content);
        });
      },
    });
  }

  ngOnDestroy() {
    window['tinymce'].remove(this.editor);
  }
}

The Problem

When I try to load up my angular app and navigate to a page containing the HtmlEditorComponent, I get the following error.

app.bundle.js:28831 TypeError: Cannot read property 'init' of undefined
    at HtmlEditorComponent.ngAfterViewInit (app.bundle.js:119565)
    at CompiledTemplate.proxyViewClass.View_PackageFormComponent0.detectChangesInternal (component.ngfactory.js:429)
    at CompiledTemplate.proxyViewClass.AppView.detectChanges (app.bundle.js:37864)
    at CompiledTemplate.proxyViewClass.View_PackageFormComponent_Host0.detectChangesInternal (host.ngfactory.js:27)
    at CompiledTemplate.proxyViewClass.AppView.detectChanges (app.bundle.js:37864)
    at ViewContainer.detectChangesInNestedViews (app.bundle.js:38122)
    at CompiledTemplate.proxyViewClass.View_AppComponent0.detectChangesInternal (component.ngfactory.js:83)
    at CompiledTemplate.proxyViewClass.AppView.detectChanges (app.bundle.js:37864)
    at CompiledTemplate.proxyViewClass.View_AppComponent_Host0.detectChangesInternal (host.ngfactory.js:27)
    at CompiledTemplate.proxyViewClass.AppView.detectChanges (app.bundle.js:37864)

Interestingly

If I add the following line to the top of HtmlEditorComponent:

import 'tinymce/themes/modern/theme'

... and the following line to webpack.config.js's module.loaders section:

      {test: /tinymce\/(themes|plugins)\//,
       loaders: ['imports?this=>window']},

... the page successfully loads and the editor works!
BUT
If I then navigate to a different page of the Angular app, I get the following error:

app.bundle.js:129920 Uncaught ReferenceError: tinymce is not defined
    at http://localhost:8081/__v2/static/app/app.bundle.js:129920:37
    at http://localhost:8081/__v2/static/app/app.bundle.js:131173:4
    at Object.<anonymous> (http://localhost:8081/__v2/static/app/app.bundle.js:131175:4)
    at __webpack_require__ (http://localhost:8081/__v2/static/app/app.bundle.js:20:30)
    at Object.<anonymous> (http://localhost:8081/__v2/static/app/app.bundle.js:119558:2)
    at __webpack_require__ (http://localhost:8081/__v2/static/app/app.bundle.js:20:30)
    at Object.<anonymous> (http://localhost:8081/__v2/static/app/app.bundle.js:119322:32)
    at __webpack_require__ (http://localhost:8081/__v2/static/app/app.bundle.js:20:30)
    at Object.<anonymous> (http://localhost:8081/__v2/static/app/app.bundle.js:119298:24)
    at __webpack_require__ (http://localhost:8081/__v2/static/app/app.bundle.js:20:30)

That above stack trace is originating from these lines in app.bundle.js

/*jsc
	["tinymce.modern.Theme","global!tinymce.Env","global!tinymce.EditorManager","global!tinymce.ThemeManager","tinymce.modern.modes.Iframe","tinymce.modern.modes.Inline","tinymce.modern.ui.Resize","tinymce.modern.ui.ProgressState","global!tinymce.util.Tools","global!tinymce.ui.Factory","global!tinymce.DOM","tinymce.modern.ui.Toolbar","tinymce.modern.ui.Menubar","tinymce.modern.ui.ContextToolbars","tinymce.modern.ui.A11y","tinymce.modern.ui.Sidebar","tinymce.modern.ui.SkinLoaded","global!tinymce.ui.FloatPanel","global!tinymce.ui.Throbber","global!tinymce.util.Delay","global!tinymce.geom.Rect"]
	jsc*/
	defineGlobal("global!tinymce.Env", tinymce.Env);
	defineGlobal("global!tinymce.EditorManager", tinymce.EditorManager);
	defineGlobal("global!tinymce.ThemeManager", tinymce.ThemeManager);
	defineGlobal("global!tinymce.util.Tools", tinymce.util.Tools);
	defineGlobal("global!tinymce.ui.Factory", tinymce.ui.Factory);
	defineGlobal("global!tinymce.DOM", tinymce.DOM);

The problem seems to be that the block above is trying to access tinymce but TinyMCE is only available via window['tinymce']

Any ideas? I'm in over my head here.

@bjohnson-va
Copy link
Author

bjohnson-va commented Dec 14, 2016

The solution for me was to add require('jquery'); require('tinymce/tinymce') to the main.ts file of my app, which is the webpack entrypoint.

This means that every page of my app has a dependency of both TinyMCE and JQuery.

Kind of a bummer but it works for now.

I'll leave this open in case there's a better solution but feel free to close.

@jayarjo
Copy link
Contributor

jayarjo commented Dec 18, 2016

Sorry not an Angular/Webpack specialist - is there a way of including external module, without requiring it?

@timelf123
Copy link

require.ensure() maybe @jayarjo

@fyrkant
Copy link

fyrkant commented Jan 5, 2017

Since TinyMCE 4.5.2 you should not have to use the imports/exports loader anymore, so maybe this works now if you remove those loaders? So just remove this:

{
  test: require.resolve('tinymce/tinymce'),
  loaders: ['imports?this=>window', 'exports?window.tinymce']
}

From you webpack config.

@jomarbarnobal
Copy link

how to use inline theme in angula2 ?
thank in adnance

@Afraithe
Copy link
Member

Afraithe commented May 8, 2018

There is an official Angular wrapper project now (tinymce-angular). Closing this ticket, any Angular related issues should be open in that project.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants