React-Bootstrap Form.File and bs-custom-file-input. Can't get label to change - react-bootstrap

I'm trying to get the text box label to change on my File upload. I'm using React-Bootstraps Form.File component and read that bs-custom-file-input will work. My general code is as follows
import bsCustomFileInput from "bs-custom-file-input"
then in my useEffect
useEffect(() => {bsCustomFileInput.init()}, [])
finally in my form
<Form.Group as={Row}>
<Form.File
type="file"
className="custom-file-label"
id="inputGroupFile01"
label="Upload Boundary File"
custom
/>
</Form.Group>
What am I doing wrong or missing? Nothing happens with my File input box after selecting the file. Or how do i troubleshoot? I inspected the HTML and the classes and id values look correct. How can I tell if the bsCustomFileInput.init() loaded or is being used?

Your example snippet is working on my end: https://codesandbox.io/s/lucid-swirles-2cejw?file=/src/index.js. But, it does have a z-index issue - you can take a look at styles.css in the sandbox for that.
However, I don't think you need that library for this specific requirement. You can just store the current file name in a state and control the label prop of Form.File
function App() {
const [fileName, setFileName] = useState("Upload Boundary File");
return (
<>
<Form.Group as={Row}>
<Form.File
type="file"
className="custom-file-label"
id="inputGroupFile01"
label={fileName}
onChange={(e) => setFileName(e.target.files[0].name)}
custom
/>
</Form.Group>
</>
);
}

Based on the idea shared in the answer from user 95faf8e76605e973, I ended up with the following:
My form component:
<Form key={`upload_${image_type}`}>
<div key={`${image_type}`} className="mb-3">
<Form.File
id={`upload_${image_type}`}
key={`upload_${image_type}`}
label={this.state.upload_image[`${image_type}`]["label"]}
custom
onChange={this.FileUploadHandler.bind(this, image_type)}
/>
</div>
</Form>
The fileUploadHandler function invoked on change:
FileUploadHandler = (image_type, e) => {
if (e.target.files) {
console.log(e.target.files);
let file = e.target.files[0];
if (file) {
let current_state = this.state.upload_image;
current_state[image_type]["label"] = file.name;
current_state[image_type]["file"] = file;
this.setState({ upload_image: current_state });
}
} else {
console.log("Nope");
}
};
The state set in my class component's constructor:
export class PackageInfo extends Component {
constructor(props) {
super(props);
this.state = {
upload_image: {
Wallpaper: { label: "Upload File...", file: "No file selected" },
RotationBanner: { label: "Upload File...", file: "No file selected" },
BootBanner: { label: "Upload File...", file: "No file selected" },
Installer: { label: "Upload File...", file: "No file selected" },
AppPage: { label: "Upload File...", file: "No file selected" },
Featured: { label: "Upload File...", file: "No file selected" },
RotationBanner: { label: "Upload File...", file: "No file selected" },
Logo: { label: "Upload File...", file: "No file selected" },
GameTVBanner: { label: "Upload File...", file: "No file selected" },
GameTiles: { label: "Upload File...", file: "No file selected" },
},
};
}

Related

Dropzone showing the V&X icons below the drop box

My Flask project with Dropzone implementation dont show the file upload progress bar but rather both the 'V' and 'X' icons for each file, like this (the 'v' and 'x' icons are bearly visible below the file name):
, and they appear below the drop box, together with the file name and size, instead of inside the drop box. The files gets uploaded though, but the behaviour is undesired. Has anybody encountered the same problem?
HTML part:
<form id="myProjFileUploadForm" method="post" enctype="multipart/form-data" action="{{ url_for('projects.projects_file_upload') }}">
...
<div id="myFileDropContainer" class="dropzone dz-clickable" style="visibility: hidden">
<div class="dz-default dz-message">
<button class="dz-button" type="button">
Drop files here to upload.
</button>
</div>
</div>
...
</form>
script part:
Dropzone.autoDiscover = true;
myDropzone = new Dropzone("#myProjFileUploadForm", {
autoQueue: true,
clickable: ".dropzone",
paramName: 'file',
url: '/upload',
myFileDropContainer: "#myFileDropContainer",
chunking: true,
forceChunking: true,
retryChunks: true,
retryChunksLimit: 10,
maxFilesize: 2025, // The max file size in Mbytes that is allowed to be uploaded
chunkSize: 10000000, // The chunk size in bytes
autoProcessQueue: true,
timeout: 180000000,
maxFiles: 500000
});
// The function that is invoced when files are dropped in
myDropzone.on("complete", function (file) {
let sStatus = new String(file.status);
let objThisFile = file
sStatus = sStatus.trim();
let sFileName = new String(file.name);
let sLastModifiedDate = new String(file.lastModifiedDate);
let sSize = new String(file.size);
const myObjFile = {
FileName: sFileName, LastModDate: sLastModifiedDate, Size: sSize
}
if (sStatus == 'success') {
$.ajax({
"url": "{{ url_for('projects.save_file_info_to_database') }}",
"type": 'POST',
"data": JSON.stringify(myObjFile),
"contentType": "application/json",
"dataType": 'json',
success: function (response) {
bErr = response.result;
if (bErr) {
objThisFile.status = 'error'
let sErr = response.msg.toString().trim();
if (sErr.length > 0) {
//alert(sErr);
}
}
else {
myDrawFileTable();
}
}
})
}
else {
let sErr = "The following file failed to upload: " + sFileName;
//alert(sErr);
}
});

Vee-validate: how use validate props callback

I'm using vee-validate to validate an input. The validation is custom, as if the input is not valid, a modal is shown and the input value is reset.
I've managed to implement this logic, calling this.$refs.provider.validate(value) inside the handler of #change input event.
However, I've also tried to use the "validate" props callback provided by the ValidationProvider but alas without success. It would be possible to use that for a logic like the one I've described?
My current code:
<template>
<div>
<ValidationProvider
:rules="rules"
v-slot="{ errors, valid }"
ref="provider"
:name="name"
slim
>
<b-form-input
ref="inputField"
:value="inputValue"
:key="inputKey"
#change="changeInput"
v-bind="$attrs"
:placeholder="name"
:state="errors[0] ? false : valid ? true : null"
lazy
type="number"
/>
</ValidationProvider>
<div>
<b-modal hide-header ok-only :id="modalId">
Modal body
</b-modal>
</div>
</div>
</template>
<script>
import { ValidationProvider } from "vee-validate";
export default {
components: {
ValidationProvider,
},
props: {
inputIndex: {
type: String,
required: true,
},
name: {
type: String,
required: true,
},
rules: {
type: [String, Object],
default: "",
},
},
data() {
return {
inputKey: 0,
modalId: "modal" + this.inputIndex,
};
},
computed: {
inputValue: function () {
return this.$store.getters["form/getMisuraN"](this.inputIndex);
},
},
watch: {},
methods: {
changeInput: async function (value) {
await this.updateinput(value);
//other logic not relevant to the issue
},
async updateinput(value) {
const { valid } = await this.$refs.provider.validate(value);
if (!valid) {
value = "";
this.$bvModal.show(this.modalId);
}
this.$store.dispatch("setInputValue", {
index: this.inputIndex,
value: value,
});
this.inputKey++;
},
},
};
</script>
What I'd like to do:
<template>
<div>
<ValidationProvider
:rules="rules"
v-slot="{ errors, valid, validate }"
ref="provider"
:name="name"
slim
>
[...]
</template>
<script>
[...]
methods: {
// use the validate function instead of calling this.$refs.provider.validate(value) inside the // #change handler method
}
</script>
You can!
Get the validate out of the slot for the VP, and pass it to your changeInput event:
<ValidationProvider
:rules="rules"
v-slot="{ errors, valid, validate }"
ref="provider"
:name="name"
slim
>
<b-form-input
ref="inputField"
:value="inputValue"
:key="inputKey"
#change="changeInput($event,validate)"
v-bind="$attrs"
:placeholder="name"
:state="errors[0] ? false : valid ? true : null"
lazy
type="number"
/>
</ValidationProvider>
Then in your changeInput function you'd do something like this:
changeInput: async function (value,validate) {
await this.updateinput(value,validate);
//other logic not relevant to the issue
},
async updateinput(value,validate) {
const { valid } = await validate(value);
if (!valid) {
value = "";
this.$bvModal.show(this.modalId);
}
/...
}

Vue.js component conflict in laravel blade view

I have 2 of the same components in my laravel blade view, but they are conflicting.
What i'm trying to accomplish:
I've made a vue component that uploads a file to firebase and stores it in my database. In my blade view i have 2 places where i want to use this component. I configure the component with props so the component knows where to store the file.
What going wrong:
Every time i try to upload a file with the second component, i fire the function in the first component. How do i fix that the components can't conflict?
My laravel balde view:
component 1
<uploadfile
:key="comp100"
:user_data="{{ Auth::user()->toJson() }}"
store_path="/users/{{ Auth::user()->username }}/settings/email_backgrounds"
:store_route="'settings.project_email'"
:size="1000"
fillmode="cover"
></uploadfile>
component 2
<uploadfile
:key="comp200"
:user_data="{{ Auth::user()->toJson() }}"
store_path="/users/{{ Auth::user()->username }}/settings/email_backgrounds"
:store_route="'settings.project_email'"
:size="1000"
fillmode="cover"
></uploadfile>
The Vue component:
<template>
<div class="vue-wrapper">
<FlashMessage position="right top"></FlashMessage>
<div v-if="loading" class="lds-dual-ring"></div>
<div class="field">
<div class="control">
<label class="button main-button action-button m-t-20" for="uploadFiles"><span style="background-image: url('/images/icons/upload.svg')"></span>Kies bestand</label>
<input type="file" name="uploadFiles" id="uploadFiles" class="dropinput" #change="selectFile">
</div>
</div>
</div>
</template>
<script>
import { fb } from '../../firebase.js';
export default {
data() {
return {
fileObject: {
filePath: null,
url: null,
file: null,
resizedPath: null
},
loading: false
};
},
mounted() {
console.log(this.size)
console.log(this.fillmode)
},
props: [
'user_data',
'store_path',
'store_route',
'size',
'fillmode'
],
methods: {
selectFile(event)
{
var file = event.target.files[0];
this.fileObject.file = file
this.fileObject.filePath = this.store_path + '/' + file.name
this.fileObject.resizedPath = this.store_path + '/resized-' + file.name
if(file.type == 'image/png' || file.type == 'image/jpeg')
{
this.uploadFile(this.fileObject)
} else {
this.flashMessage.success({
title: 'Oeps!',
message: 'De afbeelding moet een png of een jpeg zijn!',
blockClass: 'success-message'
});
}
},
uploadFile(fileObject)
{
var vm = this
console.log(fileObject)
var storageRef = fb.storage().ref(fileObject.filePath)
var uploadTask = storageRef.put(fileObject.file)
this.loading = true
uploadTask.on('state_changed', function(snapshot){
var progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100;
},function(error) {
}, function() {
var resizeImage = fb.functions().httpsCallable('resizeImage')
resizeImage({filePath: fileObject.filePath, contentType: fileObject.file.type, watermark: false, size: vm.size, fit: vm.fillmode}).then(function(result){
var downloadRef = fb.storage().ref(fileObject.resizedPath);
downloadRef.getDownloadURL().then(function(url){
fileObject.url = url
vm.loading = false
vm.storeImage(fileObject)
}).catch(function(error){
console.log(error)
})
}).catch(function(error){
});
});
},
storeImage(file)
{
axios.post('/api/app/store_file', {
api_token: this.user_data.api_token,
user: this.user_data,
file: file,
storeRoute: this.store_route
}).then((res) => {
location.reload()
}).catch((e) => {
});
}
}
}
</script>
Does someone know how to fix this?

React, passing image from this.state to component

Hej,
As I'm beginner in React. I have a problem of displaying my image passed from state to component.
App.js
this.state = {
projects: [
title: 'xxx',
image: require(../src/img/landscape.jpg)
]
}
<Works projects={this.state.projects}/>
Work.jsx
{this.props.project.title}
{this.props.project.image}
Title is displaying without any problems but image doesnt appear. Do I need to bind it in another way???
First of all, the state must be written like this:
state = {
projects: [
{ title: 'xxx',
image: require("../src/img/landscape.jpg")
}
]
}
now the work.js will contain the following code:
<div>
{this.state.projects.map((item, index) => {
return (
<div key={index}>
<p>{item.title}</p>
<img src={item.image} />
</div>
)})
}
</div>
Is your state like that you gave in your question or is it like that?
state = {
projects: [
{
title: "xxx",
image: require( "../src/img/landscape.jpg" ),
},
],
}
With your code at least you should see the path of the image. But, if you want to see the image you need to use <img>.
<div>
{
props.projects.map( project => (
<div>
<p>{project.title}</p>
<img src={project.image} />
</div>
) )
}
</div>

Remote Validation in jQuery not validating

This form will INSERT both an email and password into my MYSQL db
First, I am trying to validate an email remotely to make sure it does not exists, and also that
the Pswd and Pswd2 are equal.
the script writes to the db, but the validation is not working. I am new to JQ and Ajax so any help would be apprecated.
Thanks.
FORM:
<link rel="stylesheet" href="http://code.jquery.com/mobile/1.0.1/jquery.mobile-1.0.1.min.css" />
<script src="http://code.jquery.com/jquery-1.6.4.min.js"></script>
<script src="http://code.jquery.com/mobile/1.0.1/jquery.mobile-1.0.1.min.js"></script>
<script src="jquery.validate.js" type="text/javascript"></script>
<script src="http://ajax.aspnetcdn.com/ajax/jquery.validate/1.9/additional-methods.min.js"></script>
...
<div data-role="content">
<form id="AddUser" class="ui-body ui-body-a ui-corner-all" data-ajax="true" >
<fieldset>
<div data-role="fieldcontain">
<label for="Email">Email Address:</label>
<input id="Email" type="email" />
<label for="Pswd">Password:</label>
<input id="Pswd" type="password" />
<label for="Pswd2">Confirm Password:</label>
<input id="Pswd2" type="password" />
</div>
<button type="submit" id="submit" data-theme="b" name="submit" value="submit-value">Submit</button>
</fieldset>
</form>
</div>
...
below is the js inside the document:
<script>
$(document).ready(function() {
var validator =
$('#AddUser').validate({
rules: {
Pswd: {
required: true,
},
Pswd2: {
required: true,
equalTo: "#Pswd"
},
Email: {
required: true,
email: true,
remote: "process/ValidateEmail.php"
}
},
messages: {
Pswd: {
required: "Provide a password",
},
Pswd2: {
required: "Repeat your password",
equalTo: "Enter the same password as above"
},
Email: {
required: "Not A Valid Email Address",
remote: "already in use"
}
}
}); // end var validator
if (validator)
{
$("#AddUser").submit(function(){
//make Variables
var emailVar =$('input[id=Email]').val();
var pswdVar = $('input[id=Pswd]').val();
var pswdconfirm = $('input[id=Pswd2]').val();
var querystring = "Email="+emailVar+"&Pswd="+pswdVar;
$.post("process/AddUser.php",querystring);
}); //end submit()
}; // end if validator
}); //end ready()
</script>
the Validator file (ValidateEmail.php)
<?php
$UserEmail = $_POST["Email"];
include "connection.php";
$sqlEmail= mysql_query("Select EmailAddress from USERS where EmailAddress='$UserEmail'");
$EmailCheck=mysql_fetch_array($sqlEmail);
if (mysql_num_rows($EmailCheck) > 0) {
echo json_encode(true);
} else {
echo json_encode(false);
}
?>
I went back to the code after some research and found it riddled with errors in both the js and the php validation:
<script>
$(document).ready(function()
{
var validator = $("#AddUser").validate({
rules: {
Email: {
required: true,
email: true,
remote: "process/ValidateEmail.php"
},
Pswd: {
required: true,
},
Pswd2: {
required: true,
equalTo: "#Pswd"
},
},
messages: {
Pswd: {
required: "Provide a password",
},
Pswd2: {
required: "Repeat your password",
equalTo: "Password Mismatch"
},
Email: {
required: "Invalid Email",
remote: jQuery.format("{0} is already used")
}
},
// the errorPlacement has to take the table layout into account
errorPlacement: function(error, element) {
error.appendTo(element.parent().next());
},
// specifying a submitHandler prevents the default submit, good for the demo
submitHandler: function() {
//make Variables
var emailVar =$('input[id=Email]').val();
var pswdVar = $('input[id=Pswd]').val();
var pswdconfirm = $('input[id=Pswd2]').val();
var querystring = "Email="+emailVar+"&Pswd="+pswdVar;
$.post("process/AddUser.php",querystring);
$('#AddUser').clearForm();
return false;
},
// set this class to error-labels to indicate valid fields
success:
function(label) {
label.html(" ").addClass("checked");
}
});
});
</script>
email: {
required: true,
email: true,
remote: {
url: "check-email.php",
type: "post",
data: {
email: function() {
return $("[name='email']").val();
}
}
}
},
and the php must look like this:
$email= $_POST['email'];
include 'connect.php';
$email = trim(mysql_real_escape_string($email));
$query = mysql_query("SELECT COUNT(id) FROM users WHERE email = '$email'") or die(mysql_error());
echo (mysql_result($query, 0) == 1) ? 'false' : 'true';
be careful not to echo just false or true it must be echoed like this 'false' or true

Resources