How to include and use tinymce in a svelte component? - tinymce

I want to include an external rtf component in my svelte app.
I tried adding tinymce using the cdn in template.htm and then creating the following svelte component. The editor renders, however I can't get data into or out of the editor.
<script>
import { onMount, tick } from 'svelte'
export let label = ''
export let value = ''
$: console.log('value', value)
onMount(() => {
tinymce.init({
selector: '#tiny',
})
})
</script>
<p>
<label class="w3-text-grey">{label}</label>
<textarea id="tiny" bind:value />
</p>

Super old but encountered this today and found a solution.
Solution:
<svelte:head>
<script src="https://cdn.tiny..."></script>
</svelte:head>
<script>
import {onMount} from 'svelte';
let getHTML;
let myHTML;
onMount(() => {
tinymce.init({
selector: '#tiny'
})
getHTML = () => {
myHTML = tinymce.get('tiny').getContent();
}
})
</script>
<textarea id="tiny" bind:value />
<!-- click to get html from the editor -->
<button on:click={getHTML}>Get HTML from TinyMCE</button>
<!-- html is printed here -->
{myHTML}
Explanation:
My initial thought was to bind per normal with
<textarea bind:value></textarea>
but that doesn't work I think because tinyMCE is doing complicated stuff in the background. Instead of adding the cdn reference in template.htm I used <svelte:head> so it only is loaded for this component. The function tinymce.get('...').getContent() must be called to get the contents of the editor, but it requires tinyMCE, so it must be called within the onMount. So I define a function getHTML within onMount. Now getHTML can be used anywhere to assign the contents of the editor to myHTML.

step one:
run this command on in your terminal
npm install #tinymce/tinymce-svelte
(reference for installation : https://www.tiny.cloud/docs/integrations/svelte/)
step two :
<script>
import { onMount } from 'svelte';
let myComponent;
let summary='';
onMount(async()=>{
const module=await import ('#tinymce/tinymce-svelte');
myComponent=module.default;
})
</script>
step three :
<svelte:component this={myComponent} bind:value={summary}/>
{#html summary}

Related

Pass event options to on:event directive

Is it possible to pass event options to a svelte on:* directive?
To register an event listener with options I currently use:
<script lang="ts">
import { onMount } from "svelte"
let root: HTMLElement
onMount(() => {
const touchHandlerOptions = {
passive: true,
}
root.addEventListener("touchstart", handleTouchStart, touchHandlerOptions)
})
</script>
<div bind:this={root} />
Wondering if this could be refactored to pass the options in an on:* directive directly?
There is no way to pass options directly, but you can use event-modifiers:
<div on:touchstart|passive={handleTouchStart}>
See docs

import multiple components with one Line (Next js)

I am trying to call multiple components into a page in the same line
in the index.js file, it is importing the components and exporting them
import Header from "./Header/Header";
import Navbar from "./Navbar/Navbar";
const exportedObject = {
Header,
Navbar,
};
export default exportedObject;
and adding the imports to the page
import { Header, Navbar } from "../components";
<div>
<Header title="about page" />
<Navbar />
<h1>About</h1>
<p>THIS is the about page</p>
</div>
I keep getting this error
Error: Element type is invalid: expected a string (for built-in
components) or a class/function (for composite components) but got:
undefined. You likely forgot to export your component from the file
it's defined in, or you might have mixed up default and named imports.
trying to get it working this set-up but I don't know what I have done wrong
EDIT:
this is how I am exporting the files
export function Navbar() {
return (
<div>
<h1>this is a navbar</h1>
</div>
);
}
In the index file
export * from "./Header/Header";
export * from "./Navbar/Navbar";
You should export default your component
export default function Navbar() {
return (
<div>
<h1>this is a navbar</h1>
</div>
);
}
and remove default export in exportedObject component
const exportedObject = {
Header,
Navbar,
};
export exportedObject;

vue-chartjs and custom legend using generateLegend()

The generateLegend() wrapper does call the legendCallback defined in my Vue code but I'm lost to how to render the custom HTML in vue-chartjs. What do I do with htmlLegend as described in the vue-chartjs api docs like here.
Here is the line chart component I'm trying to render with a custom HTML object.
import { Line, mixins } from 'vue-chartjs'
const { reactiveProp } = mixins
export default {
extends: Line,
mixins: [reactiveProp],
props: ['chartData','options'],
data: () => ({
htmlLegend: null
}),
mounted () {
this.renderChart(this.chartData, this.options);
this.htmlLegend = this.generateLegend();
}
}
Here is my vue template
<template>
<div class="col-8">
<line-chart :chart-data="datacollection" :options="chartOptions"></line-chart>
</div>
</template>
Well, htmlLegend holds the markup of the generated legend... so you can just put it into your tag via v-html
<template>
<div class="col-8">
<div class="your-legend" v-html="htmlLegend" />
<line-chart :chart-data="datacollection" :options="chartOptions"></line-chart>
</div>
</template>
mounted() {
this.renderChart( this.chartData , this.options );
var legend = this.generateLegend();
this.$emit('sendLegend', legend)
}
and then in the vue file add a new div to show the legend and also listen to the event to get the legend data
<div class="line-legend" v-html="chartLegend"></div>
<line-chart #sendLegend="setLegend" :chart-data="datacollection" :options="chartOptions"></line-chart>
and also add this to the data
chartLegend: null,
and you also need a method
setLegend (html) {
this.chartLegend = html
},

Load external js file, then immediately reference the created object [Vuejs2]

I'm loading the Paypal smart button into a vue component. I've tried loading the external Paypal js script, which appears to create a paypal object.
However when trying to access the paypal object, I get this error:
found in
---> <PaypalButton> at resources/assets/js/components/PaypalButton.vue
<Root>
After the page is loaded, I can successfully console.log(paypal) in chrome dev tools console window, and I can also successfully create a button in vue to also access it, but it does not appear to be able to referenced in the mounted hook.
Here is the code:
<template>
<div class="paypal-button-wrapper">
<div id="paypal-button-container"></div>
<button #click="showPaypal">Clicking this successfully renders the button</button>
</div>
</template>
<script>
export default {
data: () => ({
}),
mounted: function () {
let paypalScript = document.createElement('script');
paypalScript.setAttribute('src', 'https://www.paypal.com/sdk/js?client-id=AUo4kSgRdH44poEYLQwPdqM24oN8nQc4Jm1HAkWs5vQTAMGu-BBlpfN4xnMDEzSGfj4wjwOy6eLtNKyv&currency=USD');
document.head.appendChild(paypalScript);
this.showPaypal(); // fails to render the paypal button, with reference error
},
methods: {
showPaypal: function() {
paypal.Buttons().render('#paypal-button-container');
}
}
};
</script>
The solution is to use paypalScript.onload. I'm not sure if this is the most direct method, but it does work.
mounted: function () {
let paypalScript = document.createElement('script');
paypalScript.setAttribute('src', 'https://www.paypal.com/sdk/js?client-id=SB_ID&currency=USD');
document.head.appendChild(paypalScript);
var that = this;
paypalScript.onload = function () {
that.showPaypal();
};
},
Reference: Run the method of the Vue component after the external script is loaded

How to Integrate MathJax with Ionic2

I'm getting template parsing errors while integrating MathJax into Ionic2 please help me with this,
package.json
"dependencies": {
.....
"mathjax": "^2.7.0"
},
home.ts
import mj from "mathjax";
home.html
<ion-card-title> Name </ion-card-title>
<span> When $a \ne 0$, there are two solutions to \(ax^2 + bx + c = 0\) and they are
$$x = {-b \pm \sqrtb^2-4ac \over 2a.}$$</span>
<button (click)= render()> Render Katex</button>
<script type="text/x-mathjax-config">
MathJax.Hub.Config({
tex2jax: 'inlineMath: [['$','$'], ['\\(','\\)']]}
});
</script>
<script type="text/javascript" async src="../../../node_modules/mathjax/MathJax.js?config=TeX-MML-AM_CHTML"></script>
https://www.npmjs.com/package/#types/mathjax
You need to install typescript declarations.
Try
npm install #types/mathjax --save
check out this question
I have been googling "Integrating MathJax in ionic 3 offline" for last 2 days. All I found that is I have to use a directive to achieve that. But this approach is not fast for such an app which has lots of mathematical equation. So I came up with another solution:
download MathJax offline file from here, extract and rename that with MathJax and place the whole folder in www/assets folder of your ionic app.
add the code given below in the head section of index.html file
<script type="text/x-mathjax-config">
MathJax.Hub.Config({
imageFont: null,
extensions: ["tex2jax.js"],
jax: ["input/TeX","output/HTML-CSS"],
tex2jax: {inlineMath: [["$","$"],["\\(","\\)"]]}
});
</script>
<script type="text/javascript" async
src="assets/MathJax/MathJax.js">
</script>
now for every page where you want to load mathematical equation, just paste the code below.
ionViewDidEnter() {
eval('MathJax.Hub.Queue(["Typeset", MathJax.Hub])');
}
By doing these three steps you will have integrated MathJax successfully.
But the problem is the size of MathJax folder is so big. You can reduce the size up to 3mb by just having the following directories and files
MathJax.js
extensions
fonts
HTML-CSS
TeX
eof
otf
svg
jax
element
input
TeX
output
HTML-CSS
autoload
config.js
fonts
TeX
imageFonts.js
jax.js
In your index.html file, add following script...
`
<script type="text/x-mathjax-config">
MathJax.Hub.Config({
showProcessingMessages: false,
tex2jax: { inlineMath: [['$','$'],['\\(','\\)']] }
});
</script>
<script type="text/javascript" async src="https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-MML-AM_HTMLorMML">
</script>
Then make a directive for mathjax as follows
import {Directive, ElementRef, Input} from '#angular/core';
declare var MathJax: {
Hub: {
Queue: (param: Object[]) => void
}}
#Directive({selector: '[MathJax]'})
export class MathJaxDirective {
#Input('MathJax') MathJaxInput: string = "";
constructor(private el: ElementRef) {
}
ngOnChanges() {
this.el.nativeElement.innerHTML = this.MathJaxInput;
MathJax.Hub.Queue(["Typeset", MathJax.Hub, this.el.nativeElement]);
}
}
Then in app.module.ts
import {MathJaxDirective} from "... to use it in you entire app
For a condition if you have multiple modules then make a commonModule something like
import { NgModule } from "#angular/core";
import { MathJaxDirective } from "./directives/MathJax.directive";
#NgModule({
declarations: [MathJaxDirective],
exports: [MathJaxDirective]
})
export class CommonModule { }
and import this module in the required module
Now you are good to go
just in your .html
<div [Mathjax]="sometxt">{{ sometxt }}</div>
and in your .ts
sometxt: string = "$$someLatex"
Hope, this will help someone