How do I integrate JS SDK into ReactJS? - javascript

I am trying to integrate QuickBlox chat JS sample app into ReactJS app.
The JS sample app has App.js file that looks like this, it uses templates using underscore.js
App.js
function App(config) {
this._config = config;
// Elements
this.page = document.querySelector('#page');
this.userListConteiner = null;
this.init(this._config);
this.loading = true;
}
// Before start working with JS SDK you nead to init it.
App.prototype.init = function (config) {
// Step 1. QB SDK initialization.
QB.init(config.credentials.appId, config.credentials.authKey, config.credentials.authSecret, config.appConfig);
};
App.prototype.loadWelcomeTpl = function () {
var content = document.querySelector('.j-content'),
welcomeTpl = helpers.fillTemplate('tpl_welcome');
helpers.clearView(content);
content.innerHTML = welcomeTpl;
};
// QBconfig was loaded from QBconfig.js file
var app = new App(QBconfig);
Templates in index.html
<script type="text/template" id="tpl_welcome">
<div class="content__title j-content__title j-welcome">
Welcome to QuickBlox chat sample!
</div>
<div class="notifications j-notifications hidden"></div>
<div class="content__inner j-content__inner">
<div class="welcome__message">
<p>Please select you opponent to start chatting.</p>
</div>
</div>
</script>
How do I use the above in my React App
const ChatApp = () => {
return (
);
}
export default ChatApp;

Generally you should get template from
<script type="text/template">
...
</script>
and return it from your component.
Of course you should implement also business code (logic) in component code.
You can split entire sample to few small components like LoginContainer, LoginForm, Dashboard, WelcomeScreen etc...
Good start point are script templates from QuickBlox sample - each template is one React component.

Related

Why am I getting 'Uncaught TypeError: window[i] is not a function' when submitting authorize.net's AcceptUI form?

I'm trying to use the authorize.net AcceptUI hosted form in a Vue.js component. https://developer.authorize.net/api/reference/features/acceptjs.html#Integrating_the_Hosted_Payment_Information_Form
The button to launch the form and the form show up correctly. After entering some test payment information and hitting submit, the form kind or reloads but doesn't disappear as it should. In the console I get the error AcceptUI.js:1 Uncaught TypeError: window[i] is not a function.
The relevant section of the AcceptUI script is this:
A = function(t) {
"function" == typeof i ? i.call(null, t) : window[i](t)
};
I have a responseHandler function defined. I'm not sure why it's not working. I stripped the code down to be almost identical to the sample that authorize.net provides but I'm assuming something with Vue.js or Typescript is interfering.
Please ignore any unrelated issues with the code. I'm only concerned about getting the responseHandler to work then I'll build out the rest of the functionality.
<template>
<div>
<form id="paymentForm" method="POST">
<button type="button"
class="AcceptUI"
data-billingAddressOptions='{"show":true, "required":false}'
data-apiLoginID="<redacted>"
data-clientKey="<redacted>"
data-acceptUIFormBtnTxt="Submit"
data-acceptUIFormHeaderTxt="Card Information"
data-responseHandler="responseHandler">Pay
</button>
</form>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
import Component from 'vue-class-component';
#Component
export default class SubscriptionManager extends Vue {
protected responseHandler(response: any) {
console.log(response);
}
protected paymentFormUpdate(opaqueData: any) {
const dataDescriptor: any = document.getElementById("dataDescriptor");
dataDescriptor.value = opaqueData.dataDescriptor;
const dataValue: any = document.getElementById("dataValue")
dataValue.value = opaqueData.dataValue;
// If using your own form to collect the sensitive data from the customer,
// blank out the fields before submitting them to your server.
const cardNumber: any = document.getElementById("cardNumber");
cardNumber.value = "";
const expMonth: any = document.getElementById("expMonth")
expMonth.value = "";
const expYear: any = document.getElementById("expYear")
expYear.value = "";
const cardCode: any = document.getElementById("cardCode")
cardCode.value = "";
const paymentForm: any = document.getElementById("paymentForm")
paymentForm.submit();
}
}
</script>
I just ran into this same problem today. My problem was that the function named in data-responseHandler couldn't be found when it was time to execute the response callback. I had defined data-responseHandler="authnetResponseHandler" but forgot to define function authnetResponseHandler(response) before testing it.
https://developer.authorize.net/api/reference/features/acceptjs.html#Handling_the_Response

Insert a script tag inside template Vue

I'm creating a integration with a payment service.
The payment service provides me a form with a script tag inside, I want to insert that form with script tag inside my component template,
but vue doesn't allow the insertion of tag script within a template, how can I insert that form with script tag inside my template component?
the form with checkout of payment service:
<form action="http://localhost:8081/api/v1/payment/" method="POST">
<script
src="https://www.mercadopago.com.br/integrations/v1/web-tokenize-checkout.js"
data-public-key="KEY"
data-transaction-amount="14.90">
</script>
</form>
The expected result:
My component:
<template>
<div id="dashboard">
<form action="http://localhost:8081/api/v1/payment/" method="POST">
<script
src="https://www.mercadopago.com.br/integrations/v1/web-tokenize-checkout.js"
data-public-key="KEY"
data-transaction-amount="14.90">
</script>
</form>
</div>
</template>
<script>
import { mapState } from "vuex";
export default {
data() {
return {}
},
}
</script>
You can use an element reference and vanilla JS to add the relevant tag to the dom.
<form ref="myform">
...
</form>
mounted() {
let foo = document.createElement('script');
foo.setAttribute("src","https://www.mercadopago.com.br/integrations/v1/web-tokenize-checkout.js");
foo.setAttribute("data-transaction-amount", "14.90")
this.$refs.myform.appendChild(foo);
}
I know this is a bit old but I came across with this problem with MercadoPago and TommyF's answer really solved it. But in my case the data-transaction-amount needed to be updated dynamically depending on users choices... So if anyone facing this, my workaround was to put it inside updated(), set an id to script tag and verify if id exists. Existing, I remove by id and all .mercadopago-button. PS: I'm newbie on JS and Vue.
let existingScript = document.getElementById('mpScript');
let existingButtons = document.getElementsByClassName('mercadopago-button');
if(existingScript) {
existingScript.remove();
while(existingButtons.length > 0) {
existingButtons[0].parentNode.removeChild(existingButtons[0]);
}
}
let script = document.createElement('script');
script.setAttribute("src", "https://www.mercadopago.com.br/integrations/v1/web-tokenize-checkout.js");
script.setAttribute("data-transaction-amount", this.total);
script.setAttribute("data-public-key", 'KEY');
script.setAttribute("id", "mpScript");
this.$refs.mpCheckout.appendChild(script);

override widget in odoo stock

In stock module the Barcode Scanner page is handled by widget.js and picking.xml through qweb.
I need to override the behaviour in order to add functionalities. So far I've been able to override the xml:
<templates id="template" xml:space="preserve">
<t t-extend="PickingEditorWidget">
<t t-jquery="#js_packconf_select" t-operation="after">
<p>Hello World!</p>
</t>
</t>
</templates>
but about the js part I'm stuck.
I need to override the behaviour of some functions inside PickingEditorWidget but in widget.js it is first contained inside the object openerp.stock and then the whole openerp.stock is overwritten with a function:
openerp.stock = function(openerp) {
openerp.stock = openerp.stock || {};
openerp_picking_widgets(openerp);
}
I've seen this kind of code is in every module, then, how could I change how (for example) this function works without have to rewritten the whole stock/widget.js with my small changes?
this.$('.js_pack_configure').click(function(){
....
})
I am not JS expert and I couldn't figure it out...
EDIT:
I put in my module's manifest the stock module in dependances, now I see the PickingEditorWidget object but still I can't make it work my changes
my code (widget.js) is:
function openerp_picking_widgets_extended(instance){
var module = instance.mrp_extended;
module.PickingEditorWidgetExtended = instance.stock.PickingEditorWidget.include({
renderElement: function(){
this.$('.js_pack_configure').click(function(){
<my code>
});
this.$('.js_validate_pack').click(function(){
<my code>
});
this._super();
},
});
}
openerp.mrp_extended = function(openerp) {
openerp.mrp_extended = openerp.mrp_extended || {};
openerp_picking_widgets_extended(openerp);
}
I fixed my code this way:
....
module.PickingEditorWidgetExtended = instance.stock.PickingEditorWidget.include({
renderElement: function(){
this._super();
....

Aurelia with Standalone library integration

I'm working on aurelia+scheduler poc. I have found one standalone js library for displaying meeting events. The issue is integrating this js with aurelia. I'm using jspm for downloading project dependencies.
Has anybody tried to integrate a standalone js library with aurilia.
Below is the library that I'm trying to integrate.
http://javascript.daypilot.org/demo/scheduler/scalehours.html.
<ai-dialog-body>
<script>
function sample(){
var dp = new DayPilot.Scheduler("dp");
dp.startDate = new DayPilot.Date("2016-06-28");
dp.cellGroupBy = "Month";
dp.days = 1;
dp.cellDuration = 1440;
dp.timeHeaders = [
{ groupBy: "Day" },
{ groupBy: "Cell" }
];
dp.scale = "Hour";
dp.bubble = new DayPilot.Bubble();
dp.treeEnabled = true;
dp.rowHeaderWidth = 200;
dp.resources = [{"id":"test#xyz.com","name":"Test"}];
dp.events.list = [{"start":"2016-06-27T16:30:00","end":"2016-06-27T17:00:00","text":"Busy","resource":"test#xyz.com","id":2170}]
dp.cellWidth = 60;
dp.init();
}
</script>
<div id="dp"></div>
<button onclick="sample()">Ok</button>
</ai-dialog-body>
when reference 3rd party library class getting below message.
ReferenceError: sample is not defined
Have you tried to download the source and then reference it in your html:
<body aurelia-app>
<script src="jspm_packages/system.js" charset="utf-8"></script>
<!-- Place a referece to the downloaded library here -->
<script src="config.js" charset="utf-8"></script>
<script type="text/javascript">
System.import("aurelia-bootstrapper");
</script>
</body>

React: Script tag not working when inserted using dangerouslySetInnerHTML

I'm trying to set html sent from my server to show inside a div using dangerouslySetInnerHTML property in React. I also have script tag inside it and use functions defined in same inside that html. I have made example of error in JSFiddle here.
This is test code:
var x = '<html><scr'+'ipt>alert("this.is.sparta");function pClicked() {console.log("p is clicked");}</scr'+'ipt><body><p onClick="pClicked()">Hello</p></body></html>';
var Hello = React.createClass({
displayName: 'Hello',
render: function() {
return (<div dangerouslySetInnerHTML={{__html: x}} />);
}
});
I checked and the script tag is added to DOM, but cannot call the functions defined within that script tag. If this is not the correct way is there any other way by which I can inject the script tag's content.
I created a React component that works pretty much like dangerouslySetInnerHtml but additionally it executes all the js code that it finds on the html string, check it out, it might help you:
https://www.npmjs.com/package/dangerously-set-html-content
Here's a bit of a dirty way of getting it done ,
A bit of an explanation as to whats happening here , you extract the script contents via a regex , and only render html using react , then after the component is mounted the content in script tag is run on a global scope.
var x = '<html><scr'+'ipt>alert("this.is.sparta");function pClicked() {console.log("p is clicked");}</scr'+'ipt><body><p onClick="pClicked()">Hello</p></body></html>';
var extractscript=/<script>(.+)<\/script>/gi.exec(x);
x=x.replace(extractscript[0],"");
var Hello = React.createClass({
displayName: 'Hello',
componentDidMount: function() {
// this runs the contents in script tag on a window/global scope
window.eval(extractscript[1]);
},
render: function() {
return (<div dangerouslySetInnerHTML={{__html: x}} />);
}
});
ReactDOM.render(
React.createElement(Hello),
document.getElementById('container')
);
I don't think you need to use concatenation (+) here.
var x = '<html><scr'+'ipt>alert("this.is.sparta");function pClicked() {console.log("p is clicked");}</scr'+'ipt><body><p onClick="pClicked()">Hello</p></body></html>';
I think you can just do:
var x = '<html><script>alert("this.is.sparta");function pClicked() {console.log("p is clicked");}</script><body><p onClick="pClicked()">Hello</p></body></html>';
Since it's passed to dangerouslySetInnerHTML anyway.
But let's get back to the issue. You don't need to use regex to access the script tag's content. If you add id attribute, for example <script id="myId">...</script>, you can easily access the element.
Let's see an example of such implementation.
const x = `
<html>
<script id="myScript">
alert("this.is.sparta");
function pClicked() {console.log("p is clicked");}
</script>
<body>
<p onClick="pClicked()">Hello</p>
</body>
</html>
`;
const Hello = React.createClass({
displayName: 'Hello',
componentDidMount() {
const script = document.getElementById('myScript').innerHTML;
window.eval(script);
}
render() {
return <div dangerouslySetInnerHTML={{__html: x}} />;
}
});
If you have multiple scripts, you can add a data attribute [data-my-script] for example, and then access it using jQuery:
const x = `
<html>
<script data-my-script="">
alert("this.is.sparta");
function pClicked() {console.log("p is clicked");}
</script>
<script data-my-script="">
alert("another script");
</script>
<body>
<p onClick="pClicked()">Hello</p>
</body>
</html>
`;
const Hello = React.createClass({
constructor(props) {
super(props);
this.helloElement = null;
}
displayName: 'Hello',
componentDidMount() {
$(this.helloElement).find('[data-my-script]').each(function forEachScript() {
const script = $(this).text();
window.eval(script);
});
}
render() {
return (
<div
ref={helloElement => (this.helloElement = helloElement)}
dangerouslySetInnerHTML={{__html: x}}
/>
);
}
});
In any case, it's always good to avoid using eval, so another option is to get the text and append a new script tag with the original's script contents instead of calling eval. This answer suggests such approach
a little extension for Dasith's answer for future views...
I had a very similar issue but the in my case I got the HTML from the server side and it took a while (part of reporting solution where backend will render report to html)
so what I did was very similar only that I handled the script running in the componentWillMount() function:
import React from 'react';
import jsreport from 'jsreport-browser-client-dist'
import logo from './logo.svg';
import './App.css';
class App extends React.Component {
constructor() {
super()
this.state = {
report: "",
reportScript: ""
}
}
componentWillMount() {
jsreport.serverUrl = 'http://localhost:5488';
let reportRequest = {template: {shortid: 'HJH11D83ce'}}
// let temp = "this is temp"
jsreport.renderAsync(reportRequest)
.then(res => {
let htmlResponse = res.toString()
let extractedScript = /<script>[\s\S]*<\/script>/g.exec(htmlResponse)[0];
// console.log('html is: ',htmlResponse)
// console.log('script is: ',extractedScript)
this.setState({report: htmlResponse})
this.setState({reportScript: extractedScript})
})
}
render() {
let report = this.state.report
return (
<div className="App">
<div className="App-header">
<img src={logo} className="App-logo" alt="logo"/>
<h2>Welcome to React</h2>
</div>
<div id="reportPlaceholder">
<div dangerouslySetInnerHTML={{__html: report}}/>
</div>
</div>
);
}
componentDidUpdate() {
// this runs the contents in script tag on a window/global scope
let scriptToRun = this.state.reportScript
if (scriptToRun !== undefined) {
//remove <script> and </script> tags since eval expects only code without html tags
let scriptLines = scriptToRun.split("\n")
scriptLines.pop()
scriptLines.shift()
let cleanScript = scriptLines.join("\n")
console.log('running script ',cleanScript)
window.eval(cleanScript)
}
}
}
export default App;
hope this is helpful...
Just use some known XSS tricks. We just had a case where we had to inject a script and couldn't wait for the release so here goes our loader:
<img src onerror="var script = document.createElement('script');script.src = 'http:';document.body.appendChild(script);"/>

Categories

Resources