How to run script in react - javascript

Hey I have a react application and I have a input field that I would like to mask (type="password") while typing the actual password.
I have found a javascript code that does what I need but I cannot seem to make it run with React.
here is the code of the masking function:
http://pastebin.com/vqqaiDuB
but I just cant use it in my view component.
I did try to :
module.exports = MaskedPassword;
but was not able to use the class?!
I am surely missing something big...
how I import it:
import maskedInput from './../../public/MaskedPassword';
this is how my component looks like:
export default class DriversLicense extends Component {
constructor(props){
super(props);
this.state ={};
}
componentDidMount() {
maskedInput(document.getElementById("demo-field"), '\u25CF');
}
render() {
return (
<div>
<form id="demo-form" action="#">
<fieldset>
<input type="password" className="password" id="demo-field" name="pword" onChange={this.demoChange}/>
</fieldset>
</form>
</div>
);
}
}
which gives me:
this.createContextWrapper is not a function

Normally this is the way to call external libraries to make changes to components after render, I would suggest to find the react version of your library because maybe It will have problems with the binding (this). Hope this example helps.
function maskedInput(ele, symbol, obj) {
//this here is not the function
ele.value = this.someOtherFunction()
}
maskedInput.prototype = {
someOtherFunction: function(){
return "Hello"
}
}
function maskedInputGood(ele, symbol, obj) {
const someOtherFunction = function(){
return "Hello"
}
ele.value = someOtherFunction()
}
maskedInput.prototype = {
someOtherFunction: function(){
return "Hello"
}
}
var App = React.createClass({
componentDidMount() {
maskedInputGood(document.getElementById("demo-field"), '\u25CF');
maskedInput(document.getElementById("demo-field"), '\u25CF');
},
render() {
return (
<div>
<form id="demo-form" action="#">
<fieldset>
<input type="password" className="password" id="demo-field" name="pword" onChange={this.demoChange}/>
</fieldset>
</form>
</div>
);
}
})
ReactDOM.render(<App />,document.getElementById('app'))
<html>
<body>
<div id='app'></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
</body>
</html>

It seems to me the library is not properly encapsulated, or some similar problem. Have you tried using a React component like this one: https://www.npmjs.com/package/react-password-mask
Since its a React component, it will be more natural to integrate it in your code.
Does your maskedPassword library have any feature that react-password-mask is missing?

Related

Composition API with Nuxt 2 to get template refs array

I'm trying to get the array of element refs that are not in v-for. I'm using #nuxtjs/composition-api on Nuxt 2.
(Truth: I want to make an array of input elements, so that I can perform validations on them before submit)
This sounds too easy on vue 2 as $refs becomes an array when one or more compnents have the same ref name on html. However, this doesn't sound simple with composition api and trying to perform simple task with that got me stuck from long.
So to handle this scenario, I've created 1 composable function. (Soruce: https://v3-migration.vuejs.org/breaking-changes/array-refs.html#frontmatter-title)
// file: viewRefs.js
import { onBeforeUpdate, onUpdated } from '#nuxtjs/composition-api'
export default () => {
let itemRefs = []
const setItemRef = el => {
console.log('adding item ref')
if (el) {
itemRefs.push(el)
}
}
onBeforeUpdate(() => {
itemRefs = []
})
onUpdated(() => {
console.log(itemRefs)
})
return {
itemRefs,
setItemRef
}
}
Here is my vue file:
<template>
<div>
<input :ref="input.setItemRef" />
<input :ref="input.setItemRef" />
<input :ref="input.setItemRef" />
<input :ref="input.setItemRef" />
<input :ref="input.setItemRef" />
<input :ref="input.setItemRef" />
// rest of my cool html
</div>
</template>
<script>
import {
defineComponent,
reactive,
useRouter,
ref
} from '#nuxtjs/composition-api'
import viewRefs from '~/composables/viewRefs'
export default defineComponent({
setup() {
const input = viewRefs()
// awesome vue code here...
return {
input
}
}
})
</script>
Now when I run this file, I don't see any adding item ref logs. And on click of a button, I'm logging input. That has 0 items in the itemRefs array.
What's going wrong?
Nuxt 2 is based on Vue 2, which only accepts strings for the ref attribute. The docs you linked actually refer to new behavior in Vue 3 for ref, where functions are also accepted.
Template refs in Nuxt 2 work the same way as they do in Vue 2 with Composition API: When a ref is inside a v-for, the ref becomes an array:
<template>
<div id="app">
<button #click="logRefs">Log refs</button>
<input v-for="i in 4" :key="i" ref="itemRef" />
</div>
</template>
<script>
import { ref } from '#vue/composition-api'
export default {
setup() {
const itemRef = ref(null)
return {
itemRef,
logRefs() {
console.log(itemRef.value) // => array of inputs
},
}
}
}
</script>
demo
And setup() does not provide access to $refs, as template refs must be explicitly declared as reactive refs in Composition API.

Injecting dynamic HTML in React - CSS is not working

Fetching dynamic HTML from an API, the HTML is loading fine but the CSS is not working for this new HTML.
Do you I need to reload the CSS.
import React, { Component } from "react";
import Utility from "../common/Utility";
class Template extends Component {
constructor(props) {
super(props);
this.token = localStorage.getItem("token");
this.client_id = localStorage.getItem("client_id");
}
componentDidMount() {
//fetching dynamic html
Utility.ExecuteData("template", this.token, {
client_id: this.client_id
}).then(result => {
var dynamic_html = document.getElementById("dynamic_html");
dynamic_html.innerHTML = result.data[0].template;
});
}
render() {
return (
<React.Fragment>
<div id="dynamic_html" />
</React.Fragment>
);
}
}
export default Template;
It is possible to get this to work but instead of className you'll need to use the usual HTML class attribute. I've used dangerouslySetInnerHTML here, but it's the same result if you set the innerHTML of the element like you did in your question.
function Template({ html }) {
return (
<div dangerouslySetInnerHTML={{__html: html}} />
);
}
const html = '<div class="heading">With style</div>';
ReactDOM.render(
<Template html={html} />,
document.getElementById('container')
);
.heading {
font-size: 2em;
color: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="container"></div>
I can't comment so I'm posting it in an answer instead.
I don't know how the html is being returned from the API but I assume the css is either inlined or included as a file in the remote HTML.
If the latter is the case, it might be a possibility that the url to the css file is relative, so calling the url from another server would result in a 404.

Multiple forms with one submit() method by Vue

I have a few forms. Every of them have the same logic (validation, sending...) so, I want to create one method to control actions on my forms. For now my code is redundancy, because I have the same methods onSubmit() on every .vue file.
my HTML:
<div id="app">
<myform-one></myform-one>
<myform-two></myform-two>
</div>
my JavaScript (main.js - entry file in webpack):
import Vue from 'vue';
import Myform1 from './myform1.vue';
import Myform2 from './myform2.vue';
new Vue({
el: '#app',
components: {
myformOne: Myform1,
myformTwo: Myform2
}
});
and VUE components files:
myform1.vue:
<template>
<div>
<form #submit.prevent="onSubmit">
<input type="text" v-model="fields.fname11" />
<input type="text" v-model="fields.fname12" />
<button type="submit">submit</button>
</form>
</div>
</template>
<script>
let formfields = {
fname11: '',
fname12: ''
};
export default {
data() {
return {
fields: formfields
}
},
methods: {
onSubmit() {
// code responsible for reading, validating and sending data here
// ...
console.log(this.fields);
}
},
}
</script>
and myform2.vue:
<template>
<div>
<form #submit.prevent="onSubmit">
<input type="text" v-model="fields.fname21" />
<input type="text" v-model="fields.fname22" />
<input type="text" v-model="fields.fname23" />
<button type="submit">submit</button>
</form>
</div>
</template>
<script>
let formfields = {
fname21: '',
fname22: '',
fname23: '',
};
export default {
data() {
return {
fields: formfields
}
},
methods: {
onSubmit() {
// code responsible for reading, validating and sending data here
// ...
console.log(this.fields);
}
},
}
</script>
How can I create and use one, common method submitForm()? And where its code should be (good practice)?
Create a separate file which contains the logic:
// submitForm.js
export default function (fields) {
// code responsible for reading, validating and sending data here
// ...
}
Then use that logic inside the components
import submitForm from "../services/submitForm.js"
...
methods: {
onSubmit() {
submitForm(this.fields)
}
}
Vue3 (with Quasar for me but I'm sure it would work for any framework):
Say you have a parent which contains a number of forms <Forms />:
First create a composable function like so useForms.js:
import { ref } from 'vue'
const forms = ref([])
export function useForms(){
const checkForms = () => {
forms.value.forEach((form) => form.validate()
}
const addFormToFormsArray = (form) => {
forms.value.push(form)
}
return { forms, addFormToFormsArray, checkForms }
}
Then import it into <Forms />:
<template>
<Form />
<Form />
<Form />
<button #click="checkForms">Check Form</button>
</template>
<script setup>
import { useForms } from '../useForms';
const { checkForms } = useForms()
</script>
Finally, inside the <Form />:
<template>
<form ref="form">
.../stuff
</form>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { useForms } from '../useForms';
const form = ref(null)
onMounted(() => {
addFormToFormsArray(form.value)
})
const { checkForms, addFormToFormsArray } = useForms()
</script>
When performing the check function in the parent, it should go through each form and check for any issues.
There are some options. My favorite is creating a mixin vue docs mixins
export const form_functionality = {
methods: {
on_submit() {
//logic of submit
},
//here we can have other reusable methods
}
}
Then in your components use that mixin as follow:
import { form_functionality } from 'path_of_mixin'
export default {
mixins: [form_functionality]
}
In the end, what mixins has (created, methods, data etc) will be merged to the component
which uses that mixin.
So, practically you can access the mixin method like this.on_submit()

How to pass props stated in HTML to root component

I'm using a simple component in React for two buttons in an existing HTML/JavaScript, (not a React project) project. It looks like this:
//Submitcancel.jsx
'use strict'
class Submitcancel extends React.Component {
constructor(props) {
super(props)
console.log(props)
}
render() {
return (
<div className="form-buttons">
<div className="ibm-col-12-12">
<button id="buttonSubmit" name="buttonSubmit" value="Submit" type="submit" className="ibm-btn-pri dw-btn-blue">Submit</button>
<button value="Cancel" id="buttonCancel" name="buttonCancel" className="ibm-btn-sec dw-btn-blue">Cancel</button>
</div>
</div>
)
}
}
ReactDOM.render(
// React.createElement(Submitcancel),
// document.querySelector('#react-submit-cancel')
)
The HTML file looks like this:
<script src="https://unpkg.com/babel-standalone#6/babel.min.js"></script>
<script src="https://unpkg.com/react#16/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom#16/umd/react-dom.development.js" crossorigin></script>
<!-- Load React component. -->
<script type="text/babel" src="./js/components/Submitcancel.jsx"></script>
The component element where I would like to define the props is like this:
<div id="react-submit-cancel"></div>
If you want to grab the button texts from your HTML <div>, you need a non-react solution for that:
<div id="react-submit-cancel" submitText="Go"></div>
then in your initialization:
const el = document.querySelector('#react-submit-cancel');
const props = {
submitText: el.getAttribute("submitText") || "Submit", // default value
cancelText: el.getAttribute("cancelText") || "Cancel"
};
ReactDOM.render(React.createElement(Submitcancel, props), el)
For a pure React solution you'd have to wrap the Submitcancel component so you can pass props to it using JSX.
When you need to pass data through props, you just need to mention props id and value along with component.
In your case code will be like:
ReactDOM.render(
<Submitcancel FirstName={"first name"} LastName={"last name"}/>,
document.getElementById("react-submit-cancel")
)
Above example FirstName and LastName are two props
You can get the value in constructor inside the Submitcancel component.
constructor(props) {
super(props)
console.log(props.FirstName)
console.log(props.LastName)
}
Please follow this code:
ReactDOM.render(
<Submitcancel />,
document.getElementById("react-submit-cancel")
)

Apanding external HTML to a react component is not working

Basically I want to add an static HTML to a react component from external script.
So I'm saving the reference of this to window variable as follows:
let { PropTypes } = React;
export default class Body extends React.Component {
constructor(){
super();
let frmTrgt={};
frmTrgt.refff=this;
console.log("tthis: ",this);
window.bdyRefrence=frmTrgt;
}
static defaultProps = {
items: []
};
static propTypes = {
items: PropTypes.array.isRequired
};
render() {
return (
<div className={styles.body}>
<h1 className={styles.header}>React Seed</h1>
<p>This is an example seed app, powered by React, ES6 & webpack.</p>
<p>Here is some example data:</p>
<Menu items={this.props.items} />
<div>
<h1>Dynamic Content</h1>
<div id="myDynamicContent"></div>
</div>
</div>
);
}
}
and in my script tag in INDEX.html( Outside Script) I'm doing like following:
function addPHtml() {
try {
window.bdyRefrence.refff.refs.formTarget.insertAdjacentHTML("<p id='mhere'>paragraph 2</p>");
}catch (err){
console.log("err: ",err);
}
}
but when I'm calling addPHtml it is giving following error:
err: TypeError: Cannot read property 'insertAdjacentHTML' of undefined
at addPHtml ((index):19)
at <anonymous>:1:1
What your trying to do is not the correct way to insert the element in React, still for you requirement please refer below mentioned code
Your render function should be like
return(
<div>
<div ref="formTarget"></div>
<h1 >React Seed</h1>
<p>This is an example seed app, powered by React, ES6 & webpack.</p>
<p>Here is some example data:</p>
<div>
<h1>Dynamic Content</h1>
<div id="myDynamicContent"></div>
</div>
</div>
)
Please check Demo here Demo
In case using new React syntax (Createclass is deprecated now) use
window.refferedItem.refs.formTarget.getDOMNode().insertAdjacentHTML

Categories