How to Pass initialPreview Data in bootstrap-fileinput - laravel

I have a page that allows users to edit a property listing they had previously submitted. I've been using bootstrap-fileinput to allow users to add images, and it will use the initialPreview attribute to show images that they've already uploaded. Users can remove the initialPreview images to remove images from the dropzone, but I can't find a way to pass this info to the server, that the user has removed these initialPreview images.
I've tried uploadExtraData: function() {}
But I can't get any information about the initialPreview images. Also, I am using the Laravel 5.7 PHP framework for my website.
<div class="form-group">
<label for="additional_info" class="col-lg-12 control-label">Add Photos to Attract Lender Interest</label>
<div class="col-lg-12">
<input type="file" name="image[]" id="image" multiple class="image" data-overwrite-initial="false"
data-min-file-count="0" value="{{ $mortgage->close_date}}">
</div>
</div>
{{-- Scripts for the pretty file input plugin called bootstrap-fileinput --}}
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-fileinput/4.4.7/js/fileinput.js" type="text/javascript"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-fileinput/4.5.2/themes/fas/theme.min.js" type="text/javascript"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.11.0/umd/popper.min.js" type="text/javascript"></script>
<script type="text/javascript">
$("#image").fileinput({
overwriteInitial: false,
initialPreview: [
// IMAGE DATA
"http://digitalbroker.test/storage/properties/847%20Queen%20Street%20West,%20Toronto,%20ON,%20Canada_1.JPG",
// IMAGE DATA
"http://digitalbroker.test/storage/properties/847%20Queen%20Street%20West,%20Toronto,%20ON,%20Canada_2.JPG",
],
initialPreviewAsData: true, // identify if you are sending preview data only and not the raw markup
initialPreviewFileType: 'image', // image is the default and can be overridden in config below
initialPreviewDownloadUrl: 'http://kartik-v.github.io/bootstrap-fileinput-samples/samples/{filename}', // includes the dynamic `filename` tag to be replaced for each config
showUpload: false,
theme: 'fas',
uploadUrl: "/submit-mortgage",
uploadExtraData: function () {
return {
_token: $("input[name='_token']").val(),
};
},
allowedFileExtensions: ['jpg', 'png', 'gif', 'jpeg'],
overwriteInitial: true,
showCaption: false,
showRemove: true,
maxFileSize: 5000,
maxFilesNum: 8,
fileActionSettings: {
showRemove: true,
showUpload: false,
showZoom: true,
showDrag: false,
},
slugCallback: function (filename) {
return filename.replace('(', '_').replace(']', '_');
}
});
</script>
Right now it just removes any old images upon submit and will save any newly uploaded ones. I'd like to both keep track of what initialPreview images were not removed, and which new images were uploaded.

I know this is an older question, but for those who stumble upon it here is a solution:
When a user clicks the remove button on the initialPreview frame you can pass information from that to the server by adding additional option to fileinput which will make an Ajax call each time the remove button is clicked.
Using the question above you would need to add:
initialPreviewConfig: [
{
// This is passed to the server in the request body as key: 0
key: 0,
// This is the url that you would send a POST request to that will handle the call.
url: 'http://www.example.com/image/remove',
// Any extra data that you would like to add to the POST request
extra: {
key: value
}
}
]
You would need to create an object for each item you have within your initialPreview array.
The OP's .fileinput would become:
$("#image").fileinput({
overwriteInitial: false,
initialPreview: [
// IMAGE DATA
"http://digitalbroker.test/storage/properties/847%20Queen%20Street%20West,%20Toronto,%20ON,%20Canada_1.JPG",
// IMAGE DATA
"http://digitalbroker.test/storage/properties/847%20Queen%20Street%20West,%20Toronto,%20ON,%20Canada_2.JPG",
],
initialPreviewConfig: [
{
key: 0,
url: '/image/remove', //custom URL
extra: {
image: '847 Queen Street West, Toronto, ON, Canada_1.JPG
}
},
{
key: 1,
url: '/image/remove', //custom URL
extra: {
image: 847 Queen Street West, Toronto, ON, Canada_2.JPG
}
},
],
initialPreviewAsData: true, // identify if you are sending preview data only and not the raw markup
initialPreviewFileType: 'image', // image is the default and can be overridden in config below
initialPreviewDownloadUrl: 'http://kartik-v.github.io/bootstrap-fileinput-samples/samples/{filename}', // includes the dynamic `filename` tag to be replaced for each config
showUpload: false,
theme: 'fas',
uploadUrl: "/submit-mortgage",
uploadExtraData: function () {
return {
_token: $("input[name='_token']").val(),
};
},
allowedFileExtensions: ['jpg', 'png', 'gif', 'jpeg'],
overwriteInitial: true,
showCaption: false,
showRemove: true,
maxFileSize: 5000,
maxFilesNum: 8,
fileActionSettings: {
showRemove: true,
showUpload: false,
showZoom: true,
showDrag: false,
},
slugCallback: function (filename) {
return filename.replace('(', '_').replace(']', '_');
}
});
I hope this helps anybody who comes across it.
FYI this is my first answer on SO (please be kind :P )

Related

Implement daterange filter with serverside processing in Yajra Laravel datatables

I have an invoices table, which uses the Yajra Laravel data table. I want to filter data using 'created_at' column, which does exists in invoices table in the database but not in the table view.
Here is my datatable image:
And the code which take start and end dates:
$(function() {
$('#invoices_daterange').daterangepicker({
opens: 'left'
}, function(start, end, label) {
console.log("A new date selection was made: " + start.format('YYYY-MM-DD') + ' to ' + end.format('YYYY-MM-DD'));
});
});
Here is my datatabe JS code
$(function () {
let invoicedatatable = $('#invoicesdatable-table').DataTable({
pageLength: 100,
processing: true,
serverSide: true,
ajax: '{{ route('invoices.datatable') }}',
columns: [
{data: 'invoice_number', name: 'invoice_number'},
{data: 'partner', name: 'partner.full_name'},
{data: 'start', name: 'start'},
{data: 'end', name: 'end'},
{data: 'due', name: 'due'},
{data: 'actual_invoice_amount', name: 'actual_invoice_amount'},
{data: 'action', name: 'action', sortable: false, searchable: false},
],
lengthMenu: [
[10, 50, 100, 250, 3000, 5000],
[10, 50, 100, 250, 3000, 5000]
],
buttons: [{
extend: 'colvis',
text: '<i class="icon-three-bars"></i>',
className: 'btn bg-blue btn-icon dropdown-toggle'
}]
});
});
I did search and read most of the topics about it, but couldn't find anything to implement this.
What I want to do:
is to filter data using the 'created_at' column which is not in the view, but exists in my invoices table in the database.
How to do it?
I am not familiar with your datepicker widget, so I cannot use that in my example. But I think you should be able to adapt the following to use your datepicker.
In my example, I have two separate date fields ("from" and "to") in a form, with a "submit" button:
<div>
<form id="filter-form">
From:<input type="date" id="min-date" name="min-date">
To:<input type="date" id="max-date" name="max-date">
<input type="submit" value="Submit">
</form>
</div>
You don't need to use a form (I used a form here, because it is a simple demo).
In the page's script (the same place where the DataTable is defined), I add a "submit" function:
var url = '{{ route('invoices.datatable') }}';
$( "#filter-form" ).submit(function( event ) {
event.preventDefault();
invoicedatatable.ajax.url( url ).load();
});
I don't actually need to submit the form, so I disable the default submission using event.preventDefault();.
The line invoicedatatable.ajax.url( url ).load(); is explained below.
In my DataTable I change the basic Ajax call from this:
ajax: '{{ route('invoices.datatable') }}',
to this:
ajax: {
url: url,
type: "POST", // or 'GET' if you prefer
data: function (data) {
data.mindate = $('#min-date').val();
data.maxdate = $('#max-date').val();
}
},
This uses a DataTables function to manipulate the data option. This is the data which we will send to the server, as part of our server-side request.
I simply append two new variables to the existing data - mindate and maxdate. These contain the date range you need to use in the server, for filtering.
Note that the data variable passed into the function already contains some data, provided by DataTables for server-side processing. So, I am adding these two extra fields to that existing data.
The request sent from the browser to the server now looks like this. You can see mindate and maxdate at the bottom of the list:
{
"draw": "2",
"columns[0][data]": "id",
"columns[0][name]": "",
"columns[0][searchable]": "true",
"columns[0][orderable]": "true",
"columns[0][search][value]": "",
"columns[0][search][regex]": "false",
"columns[1][data]": "name",
"columns[1][name]": "",
"columns[1][searchable]": "true",
"columns[1][orderable]": "true",
"columns[1][search][value]": "",
"columns[1][search][regex]": "false",
... not all details shown
"order[0][column]": "0",
"order[0][dir]": "asc",
"start": "0",
"length": "10",
"search[value]": "",
"search[regex]": "false",
"mindate": "2021-06-08", // <--- mindate
"maxdate": "2021-06-16" // <--- maxdate
}
In the form submission event, there was this line:
invoicedatatable.ajax.url( url ).load();
This line causes the ajax call in the DataTable to be re-executed, and the table to be re-drawn. This is the trigger which causes the dates to be sent to the server, as part of a standard request. It's the same action as when a user clicks on a column to sort the data, or moves from one page to another page in the DataTable.
The server can process this request and extract the two date fields from the request, in the usual way. It can then use these values to filter the data, before building its response, to send back to the DataTable.

Instagram feed carousel

I want to create a carousel that contain my instagram photo on my website. It's already working with simple grid style. This is the section where I put the feed:
<div id="instagram-feed-demo" class="instagram_feed"></div>
and this is the script:
<script type="text/javascript">
(function($) {
$(window).on('load', function() {
$.instagramFeed({
'username': 'iipex_id',
'container': "#instagram-feed-demo",
'display_profile': false,
'display_biography': false,
'display_gallery': true,
'get_raw_json': false,
'callback': null,
'styling': true,
'items': 9,
'items_per_row': 3,
'margin': 1
});
});
})(jQuery);
</script>
since I want to display it as carousel, I try to put the ID and Class into carousel :
<div id="instagram-feed-demo" class="carousel instagram_feed" data-items="3" data-dots="false" data-loop="true" data-autoplay="true" data-lightbox="gallery"></div>
but it's not working. maybe I have to create another script? or I made a mistake on my carousel ?

Dropzone multiple file upload uploads 2 files at a time

I have the following code
HTML
<form action="{{ route('documents.store') }}" method="POST" class="kt-form kt-form--label-right">
#csrf
<div class="kt-portlet__body">
<div class="form-group">
<div class="dropzone dropzone-default dropzone-success" id="documents_upload" style="padding: 0;">
<div class="dropzone-msg dz-message needsclick">
<h3 class="dropzone-msg-title">Drop files here</h3>
</div>
</div>
</div>
</div>
</form>
Javascript
<script type="text/javascript">
$(document).ready(function() {
$('#documents_upload').dropzone({
url: "{{ route('documents.store') }}", // Set the url for your upload script location
paramName: "documents", // The name that will be used to transfer the file
maxFiles: 50,
maxFilesize: 4, // MB
addRemoveLinks: true,
acceptedFiles: "application/msword, application/vnd.ms-excel, application/pdf, image/*, application/vnd.openxmlformats-officedocument.wordprocessingml.document, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, image/*",
uploadMultiple: true,
headers: {
'X-CSRF-TOKEN': "{{ csrf_token() }}"
},
queuecomplete: function() {
// notify about successful upload
// window.location.replace("{{ route('client.documents.index') }}");
}
});
});
</script>
The problem
It seems like this uploads the documents on chunks, 2 at a time. So if I want to upload 8 files it makes 4 requests, each containing 2 files. I want to upload all at once, is there any easy way I can do this ? This method causes many problems, because the user may upload a large amount of documents and when half of them are ready, he can leave/refresh the page, etc. and he will have to search which documents have been uploaded and which have not.
You need to tell the dropzone to do a parallel upload in the options of your dropzone, by the quantity you want.
<script type="text/javascript">
$(document).ready(function() {
$('#documents_upload').dropzone({
url: "{{ route('documents.store') }}", // Set the url for your upload script location
paramName: "documents", // The name that will be used to transfer the file
maxFiles: 50,
maxFilesize: 4, // MB
addRemoveLinks: true,
acceptedFiles: "application/msword, application/vnd.ms-excel, application/pdf, image/*, application/vnd.openxmlformats-officedocument.wordprocessingml.document, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, image/*",
parallelUploads:10,
uploadMultiple: true,
headers: {
'X-CSRF-TOKEN': "{{ csrf_token() }}"
},
queuecomplete: function() {
// notify about successful upload
// window.location.replace("{{ route('client.documents.index') }}");
}
});
});
Let me know if it worked!!

Kendo ui grid duplicate records with custom upload button in toolbar

I know this question has been posted a few times, and i haven´t done anything else unless searching for an answer to the behavior i´m having on my grid...the problem is, the create method being called multiples times AFTER inserting the first one...so the first inserts well, the second repeats two times and so on:
I have a inline grid with two buttons on my grid, the first one just inserts "normally", the second button calls this(below) in a kendoWindow:
<div id="fileUploadWindow">
<form id="fileUploadForm" enctype="multipart/form-data" action="ficheiro.php" method="post">
<input style="font-family: roboto;" type="file" id="file" name="file">
<p id="fileUploadFormResult" style="font-family:Roboto;font-size:13px;float:left;margin-top: 15px;"></p>
<button style="display: block;margin-left: 230px;margin-top: 10px;border: solid;border-width: 1px;padding-left: 10px;background: transparent;border-color: #FF9300;font-size: 13px;font-family: roboto;padding-right: 10px;" id="idBtnEnviarFicheiro" name="nameBtnEnviarFicheiro" type="submit">Enviar</button>
</form>
</div>
It´s just a simple form with a input type file, and for this to be called, i have this method:
$(".k-grid-popup", ent.element).on("click", function ()
{
$("#fileUploadWindow").kendoWindow({
actions: ["Close"],
draggable: true,
width: "300px",
height: "65px",
modal: true,
resizable: false,
title: "Inserir Ficheiro",
visible: false,
close:function()
{
}
}).data("kendoWindow").center().open();
$('#fileUploadForm').on('submit',(function()
{
var formData = new FormData($(this)[0]);
ficheiroVal = $("#file").val().split('\\').pop();
$.ajax({
url: 'ficheiro.php',
type: "POST",
data: formData,
processData: false,
contentType: false,
success: function(data)
{
if(data === "")
{
$("#fileUploadFormResult").text("Erro!, por favor tente de novo.");
hypeDocument.getElementById("fileUploadForm").reset();
}
else
{
$("#fileUploadFormResult").text("Envio com Sucesso!.");
ficheiroValReal = data;
$('#gridBaseDados').data('kendoGrid').dataSource.add({idPai:'',tipo:ficheiroValReal, nome:ficheiroVal, dataCriacao: ''});
$('#gridBaseDados').data('kendoGrid').dataSource.sync();
}
},
error: function(data)
{
$("#fileUploadFormResult").text("Erro!, por favor tente de novo.");
}
});
return false;
}));
My grid model is this:
batch: true,
serverPaging: true,
serverSorting: true,
pageSize: 8,
schema:
{
data: "data",
model:
{
id: "idDocumento",
fields:
{
idDocumento: { editable: false, nullable: true, type: "number"},
idPai: { validation: { required: false } },
tipo: { validation: { required: false } },
nome: { validation: { required: true } },
dataCriacao: {type:"string",editable: false},
dataModificacao: {type:"string",editable: false},
}
}
}
I don´t know if ist´s relevant or not, but here is my php code:
<?php
if(isset($_POST["nameBtnEnviarFicheiro"]))
{
if( ($_POST["nameBtnEnviarFicheiro"]) && (empty($_POST['file'])))
{
echo "";
}
else
{
$temp = explode(".", $_FILES["file"]["name"]);
$newfilename = round(microtime(true)) . '.' . end($temp);
move_uploaded_file($_FILES["file"]["tmp_name"], "tabeladocumento/" . $newfilename);
echo $newfilename;
}
}
?>
So, the user clicks on the popup button, and a kendowindow appears with a input file, the users chooses a file and the FIRST time, the grid inserts the record corectly(appearing only one time)...then he closes the kendoWindow, and if he wants to insert a new file, it does...but the record appears TWO times...the create method is called two times and also my ficheiro.php is also called two times.
I´ve also used this(below) in multiple places, like in the create method..also after calling the sync() but nothing seems to work. What it could be?!
$('#gridBaseDados').data("kendoGrid").dataSource.read();
When you close you window you must destroy all widgets inside, to avoid duplicated instances.
http://docs.telerik.com/kendo-ui/intro/widget-basics/destroy
Hope this help

Using dijit.filteringselect in a Spring MVC environment

I am trying to code two filteringselects which should both change according to data entered into any of the forms.
So data entered into fs1 should trigger changes in fs2.
Data entered into fs2 should trigger changes in fs1.
I am in a spring environment which in my case means that the dojo code is in a jsp file and the filtering select fields are populated through a Controller class on the server side using #ModelAttribute annotations to make the data available as a variable in the jsp file.
I have the relation data on the Java side so it's available through the controller.
Here is what confuses me at the moment.
I am new to DOJO and the documentation on the DOJO support site is a little hard to grasp for me. I would like to see a conceptual list of what is needed to accopmplish and connect the separate stores of my filteringselects.
When there is a change in one of the filteringselects, how do I inform the controllerclass of the changes and send the data that remains in the filteringselect?
This question could also be read as: how can I call a method with input parameters that hold the data available in the edited filteringselect?
I suggest we work on this in two incremental parts:
Get the first FilteringSelect's onChange event working
Wire them up to use server data stores
The following code sample takes a Dojo Campus' codependent FilteringSelect example and simplifies it so that its data stores are local. It shows how to programmatically instantiate two FilteringSelects with the second being dependent on the first by an onChange event handler.
Can you please try running it and let me know if you get it working?
Once we get your first FilteringSelect triggering filtering on the second, I will edit to add an explanation on how to convert them to use server side data stores.
<html>
<head>
<title>Test File</title>
<link type="text/css" rel="stylesheet" href="dijit/themes/tundra/tundra.css"/>
</head>
<body class="tundra">
<label for="state">State:</label>
<input id="state">
<label for="city">City:</label>
<input id="city">
<script type="text/javascript" src="dojo/dojo.js"
djConfig="isDebug: true, parseOnLoad: true"></script>
<script type="text/javascript">
dojo.require("dijit.form.FilteringSelect");
dojo.require("dojo.data.ItemFileReadStore");
dojo.addOnLoad(function() {
var cityJson = {
label: 'name',
items: [{ name: 'Albany', state: 'NY' },
{ name: 'New York City', state: 'NY' },
{ name: 'Buffalo', state: 'NY' },
{ name: 'Austin', state: 'TX' },
{ name: 'Houston', state: 'TX' }]
};
var stateJson = {
identifier: 'abbreviation',
label: 'name',
items: [ { name: 'New York', abbreviation: 'NY' },
{ name: 'Texas', abbreviation: 'TX' } ]
};
new dijit.form.ComboBox({
store: new dojo.data.ItemFileReadStore({
data: cityJson
}),
autoComplete: true,
query: {
state: "*"
},
style: "width: 150px;",
required: true,
id: "city",
onChange: function(city) {
dijit.byId('state').attr('value', (dijit.byId('city').item || {
state: ''
}).state);
}
},
"city");
new dijit.form.FilteringSelect({
store: new dojo.data.ItemFileReadStore({
data: stateJson
}),
autoComplete: true,
style: "width: 150px;",
id: "state",
onChange: function(state) {
dijit.byId('city').query.state = state || "*";
}
},
"state");
});
</script>
</body>
</html>
in the namespace of the jsp:
xmlns:springform="http://www.springframework.org/tags/form"
sample form:
<springform:form action="#" >
<label for="country">Country:</label>
<springform:select id="country" path="country" items="${countryList}" itemLabel="country" itemValue="id"/>
<div id="citySelectDiv"></div>
</springform:form>
javascript code:
<script type="text/javascript">
<![CDATA[
dojo.require("dojo.parser");
dojo.require("dojo.data.ItemFileReadStore");
function countryChanged(dataFromServer){
//convert json to dojo filteringSelect options
var options = {
identifier: 'id',
label: 'city',
items: dataFromServer
};
var cityStore =new dojo.data.ItemFileReadStore({data : options});
// create Select widget, populating its options from the store
if (!dijit.byId("citySelectDiv")) {
//create city selction combo
new dijit.form.FilteringSelect({
name: "citySelectDiv",
store: cityStore,
searchAttr : "city",
}, "citySelectDiv");
}else{
//if already created the combo before
dijit.byId('citySelectDiv').set('value',null);
dijit.byId('citySelectDiv').store = cityStore;
}
}
Spring.addDecoration(new Spring.ElementDecoration({
elementId : "country",
widgetType : "dijit.form.FilteringSelect",
widgetAttrs : {
promptMessage: "Select a Country",
required : true,
onChange : function(){
var xhrArgs = {
url: "ajax/country/" +dijit.byId('country').get('value'),
handleAs: 'json',
load: function(dataFromServer) {
countryChanged(dataFromServer);
}
};
//make the ajax call
dojo.xhrGet(xhrArgs);
}
}
}));
Sample Controller method:
#ResponseBody
#RequestMapping("/ajax/country/{country}")
public List<City> clientSelection(#PathVariable("country") String country ) {
log.info("Country = {} ",country);
return cityService.findCitiesByCountry(country);
}

Resources