Implement Jsignature within vuejs component - javascript

I'm new to Vue and trying to implement Jsignature within a 'custom' Vuejs component.
My solution is based on: https://v2.vuejs.org/v2/examples/select2.html
It should be straight forward however I don't get it working, the solution I got so far results in the following error:
'Jsignature' is defined but never used
import Jsignature from '../../lib/jsignature
The component containing the signature.
<template>
<div>
<app-signature></app-signature>
</div>
</template>
<script>
import Signature from './signature/Signature.vue'
export default {
components: {
appSignature: Signature
}
}
</script>
The signature component.
<template>
<div id="signaturecanvas"></div>
</template>
<script>
import Jsignature from '../../lib/jsignature'
export default {
data () {
return {
signature: ''
}
},
methods: {
initial () {
var element = ('#signaturecanvas')
element.Jsignature.jSignature()
}
},
created () {
this.initial()
}
}
</script>
<style></style>

Never worked with Jsignature but I suppose you use it as a jquery plugin.
The issue you have is right at the this.$signaturecanvas. This is somehow a wrong way to get the div via jQuery.
var element = ("#signaturecanvas") or var element = $(this.$el) if you want to selected the whole component. $el refers to the identifier of the current vue component instance and basically is the first tag from the component. Choose the appropriate way depending on what you want to select and you should get it working.

Instead of importing JQuery and JSignature, I made the choice to use signature pad. https://github.com/szimek/signature_pad
This 'plug-in' is in native javascript/html5 which makes my application less constraint to external libraries like JQuery.

Related

Programmatically instantiate vuetify-components

I am trying to programmatically instantiate vuetify-components and add them to the DOM. With simple components like a v-card or v-dialoge it works fine, but it does not work with v-data-tables.
I created a codesandbox to showcase the problem: https://codesandbox.io/s/throbbing-butterfly-4ljhx?file=/src/components/MainWindow.vue
Look at the errors in the console when clicking the button to add a Table.
Can anyone help me out on how to add a table and why it throws these TypeErrors? Thanks!
Btw. I am following this guide: https://css-tricks.com/creating-vue-js-component-instances-programmatically/
You need to pass vuetify instance into extended Vue constructor same way as you do when instantiating main Vue instance...
MainWindow.vue
<template>
<v-app>
<v-btn #click="addTable" color="red">Generate Data-Table</v-btn>
<hr>
<v-btn #click="addCard">Generate simple Card</v-btn>
<v-container ref="mainContainer"></v-container>
</v-app>
</template>
<script>
import Table from "./Table.vue";
import Card from "./Card.vue";
import Vue from "vue";
import vuetify from "../plugins/vuetify";
export default {
name: "mainWindow",
components: { Table, Card },
methods: {
addTable() {
var ComponentClass = Vue.extend(Table);
var instance = new ComponentClass({ vuetify });
instance.$mount();
this.$refs.mainContainer.appendChild(instance.$el);
},
addCard() {
var ComponentClass = Vue.extend(Card);
var instance = new ComponentClass({});
instance.$mount();
this.$refs.mainContainer.appendChild(instance.$el);
}
}
};
</script>
<style>
</style>
Note: This is not recommended way of using dynamic components in Vue!
From the linked article:
In my case, I don’t know which component to insert in the template and also where to insert it. This information is only available at runtime
This is useful only when you do not know "where". If you know "where", "which" part is easily solvable with Dynamic Components

How to force Antd to append element as child element of div React renders to instead of to HTML body?

Edit:
I figured it out & posted answer below.
Original Question
I am trying to create a completely compartmentalized web application within a shadow-dom and I've been using Antd components and ran into the issue where Antd is appending drop-down options into the body tag instead of as a child of the element that React is rendering into.
To isolate this issue I've removed everything outside of just React.render & a single Antd element which still does the same thing.
I then used a different component, "react-date-picker", which works how I had hoped Antd did, where the component renders as a child of the div specified for react.
Unfortunately, Antd rendering to the body of the HTML instead of as a child makes using shadow-root pointless.
Essentially my question is:
Is this Antd's normal functionality? If not then what might I be screwing up to have this happen? If so then is there a built-in Antd option that I'm missing that will render Antd options as child elements? If that option doesn't exist within their libraries, is there a way for me to force Antd to render as a child of my shadow-root node?
Here is what I'm using to render the Antd DatePicker component:
import ReactDOM from 'react-dom';
import React from 'react';
import DatePicker from 'antd/lib/date-picker';
ReactDOM.render(<DatePicker/>, document.getElementById('entry-fields'));
Before clicking on the Antd date picker:
After clicking on it, drop down options are appended to <body> and not <div id="entry-fields>:
Here is what I'm using to render the react-date-picker component to demonstrate the functionality I expected / need:
import ReactDOM from 'react-dom';
import React from 'react';
import DatePicker from "react-datepicker";
class Example extends React.Component {
state = {
startDate: new Date()
};
handleChange = (date: any) => {
this.setState({
startDate: date
});
};
render() {
return (
<DatePicker
selected={this.state.startDate}
onChange={this.handleChange}
/>
);
}
}
ReactDOM.render(<Example/>, document.getElementById('entry-fields'));
Before clicking on the react-date-picker date picker:
After clicking on the react-date-picker date picker (the drop down options are appended as children of the element react is rendered onto):
Basically I expected Antd to render its options encapsulated within the React rendered into <div></div> but it is instead appending elements on the <body></body>.
I'm relatively inexperienced in the web-dev domain and have resorted to asking a question here after way too much time trying to find the answer on my own. I am getting extremely frustrated in web-dev in general where any question seems to yield hundreds of irrelevant medium blog posts that are not useful in any capacity... assuming that it's not just me not knowing what to search for yet to find the answers I need which could very well be the case.
Really appreciate any help in advance.
Not sure how I managed to miss this but Antd has a parameter called "getCalendarContainer" which if left blank will render options into the body of the document but if supplied with the correct parameters will render the child elements into the container of your choosing.
Going off this example: https://react-component.github.io/calendar/examples/getCalendarContainer.html
I got it working by adding this function to my component:
getCalendarContainer()
{
return this.d || document.getElementById('calendarContainer');
}
and adding this to the component in JSX:
<div id="calendarContainer" ref={n => (this.d = n as HTMLDivElement)} >
<DatePicker onChange={EntryFields.onDateChange} getCalendarContainer={this.getCalendarContainer}/>
</div>
and initializing the div tag to reference it in the component's constructor like this:
private d: HTMLDivElement;
constructor(props: any)
{
super(props);
this.d = document.createElement("div");
...
It's also worth noting that the above will not work immediately when using shadow-DOM since you need to access the node that the shadow-DOM is a child to and then use getElementById().
Something along these lines (but probably better written I hope lol)
getContainer() {
let elem = null;
let shadowContainer = document.getElementById('entryFieldsShadow') as HTMLInputElement;
if (shadowContainer != null) {
let shadowDom = shadowContainer.firstElementChild;
if (shadowDom != null) {
let shadowRoot = shadowDom.shadowRoot;
if (shadowRoot != null) {
elem = shadowRoot.getElementById("entryFieldsContainer")
}
}
}
return elem || this.d;
}
where the JSX with react-shadow's shadow root is included looks like this:
return (
<div id="entryFieldsShadow">
<root.div>
<div>
<div id="entryFieldsContainer"/>
<style type="text/css"> #import "static/1.css"; </style>
<Layout>
<Content>
{this.RowCols()}
</Content>
</Layout>
</div>
</root.div>
</div>
)
This solve my problems
<DatePicker
{...}
getCalendarContainer={triggerNode => triggerNode.parentNode}
/>

Vue-Multiselect looks like zero width text input and has no styling

I'm trying to figure out how to set up Vue-multiselect component on Laravel 5. Until now i've got a component called register.vue
and here is the part of the code where i need the component (I won't put all the code here becase it'd be too large.
<b-row align-v="center">
<multiselect
v-model="selected"
:options="options">
</multiselect>
</b-row>
Here's where i included the component in the script section
import Multiselect from 'vue-multiselect';
export default {
components: { Multiselect },
data(){
return {
selected: null,
options: ['list', 'of', 'options'],
}
}
Nevertheless, what i'm obtaining is a weird component like this one
This is how it looks when the focus is not in the component
And when the focus is in the component it only shows an input field with some bullet list which the elemtents of the array with the options are.
Does somebody know what is going on in my app? I've been a lot of time checking if there's some missed css file or stuff like that but everything seems to be OK, except that part, my component seems not be loading any style.
Thanks a lot everyone.
I noticed you included the b-row part which lets me know you have Bootstrap Vue, considering you have that whole library and all of it's CSS included (it may even contain a multiselect component of its own or use select2). It's most likely that the two stylesheets are messing with each other or one is causing the other not to init correctly or at the proper time.
I found this issue here which seems possibly like it could help you withchecking your styling. https://github.com/shentao/vue-multiselect/issues/718
Also I would get rid of all the other Vue components off that page for a minute and load in Vue Multiselect by itself exactly according to their documentation. That will let you narrow it down to the problem being a conflict between another Vue component or Laravel / when you are starting up Vue multiselect.
I use it in a PHP / Vue project currently this is my working setup with Buefy framework.
I made my own Vue component as a wrapper for multiselect which lets me scope the CSS to just its specific HTML.
<template>
<multiselect
v-model="value"
:options="options"
:placeholder="placeholder"
label="label"
track-by="value"
#input="inputChanged" />
</template>
<script>
import Multiselect from 'vue-multiselect';
export default {
components: { Multiselect },
props: {
options: {
type: [Array],
default() {
return [];
}
},
savedValue: {
type: [Array],
default() {
return [];
}
},
placeholder: {
type: [String],
default: 'Select Option...'
}
},
data() {
return {
value: null
};
},
mounted() {
this.value = this.savedValue;
},
methods: {
inputChanged(selected) {
this.$emit('selected', selected.value);
}
}
};
</script>
<style scoped>
#import '../../../../../node_modules/vue-multiselect/dist/vue-multiselect.min.css';
</style>
Then you can call the component from another file kind of like this.
<select-input
:saved-value="artistSelected"
:options="artistOptions"
:placeholder="'Choose an existing artist...'"
#selected="artistChanged"
/>
Scoping the CSS like I did will help other things from not messing with your styling.
The problem occurs because of the wrong component import statement.
In my case, the following statement gave the correct behaviour:
import Multiselect from 'vue-multiselect/src/Multiselect'

EmberJs - Is there a way to tell ember to insert the main-view after the rootElement?

Hi I would like to know if the is a way to tell ember to initialize immediately after the root Element?
For example I have this DOM Structure:
<div id="#bodyContent" class="ember-application">
<div data-name="ContentPlaceHolderMain">
</div>
<div id="ember357" class="ember-view">
</div>
</div>
But I Want ember to be first on the DOM:
<div id="#bodyContent" class="ember-application">
<div id="ember357" class="ember-view">
</div>
<div data-name="ContentPlaceHolderMain">
</div>
</div>
In my enviroment.js file I have this line:
ENV.APP.rootElement = "#bodyContent";
Is there any way to achieve this?
Ember uses appendTo to insert it's view inside root element. But you could override didCreateRootView of ember instance and change it to use prependTo. Have a look how Fastboot does this.
Update: This is an instance-initializer to overwrite didCreateRootView.
export function initialize(appInstance) {
appInstance.didCreateRootView = function(view) {
// overwrite didCreateRootView
};
}
export default {
name: 'prepend-to',
initialize
};
ember/glimmer does not provide an prependTo method. You have to implement that one on your own following the implementation of appendTo.
Please also note that didCreateRootView is a private hook. Don't expect that one to keep stable over time.
In general I would not recommend to go this path if there is any other way to achieve your goal. Please consider adding a container for ember at desired position. If you don't have control over HTML markup you might could add a container using jQuery before initializing ember.
Update 2:
import jQuery from 'jquery';
export function initialize(appInstance) {
appInstance.didCreateRootView = function(view) {
let containerId = 'ember-container';
jQuery('<div>').prop('id', containerId).prependTo(jQuery(this.rootElement));
view.appendTo(`#${containerId}`);
};
}
export default {
name: 'prepend-to',
initialize
};
This is not exactly what you've asked for but it's much easier to achieve. If your HTML markup looks like <body><div id="existing-content"></body> and body as default root element above instance initializer will add another div #ember-container before #existing-content and using this one as embers root element.
Update 3:
You find an ember-twiddle here: https://ember-twiddle.com/43cfd1ae978b810f2e7cf445f9a3d40c?openFiles=instance-initializers.root-element.js%2C
If you inspect DOM you will see that ember root element is wrapped by <div id="ember-container"></div>. This wrapper is append to rootElement. So it's before any existing content in rootElement. I guess it's not possible to define a custom index.html in ember-twiddle so I can't demonstrate this one. But you could easily test yourself.

How to get reference auto generated elements in React?

I am currently working with react but I am now stuck with an error that I don't know how to fix. I am using mCustomScroll bar and this library automatically generates an element with the id of MCSB_1. This means that I can't attach a "ref" to it. The only element that I can attach is a ref to is the parent element to the auto generated element.
For example my structure is as follows;
componentDidMount() {
$(this.refs.messagesPanel).mCustomScrollbar(); //The mCustomScrollbar is a plugin
}
render() {
return (
<div id="messagesPanel" ref="messagesPanel"></div>
);
}
The problem is: that when I call mCustomScrollbar(); the plugin auto generates a div in messagesPanel which I do not know how to access:
<div id="messagesPanel">
<div id="MCSB_1"></div>
</div>
Basically, i'm asking how do I access the "MCSB_1" if I can't attach a ref to it.
Thanks!
One option could be using jQuery's find function from your messagePanel object
componentDidMount() {
...
}
someFunction() {
let yourElement = $(this.refs.messagesPanel).find('#MCSB_1');
}

Categories

Resources