I have used Vue Dropzone to upload files before which is fairly self explanatory but I had a question about something that I don't even know is possible but here goes:
Users drags files to dropzone area and they are added to the queue
User uploads files
User then sees a table with each file as a row where they have to select a category for each file
However, I don't want to upload anything until categories have been selected for each file so instead my thought is to bind the dropzone queue to a data property.
Something like this
mounted() {
this.dropzone = new Dropzone("#dropzone", {
url: "/file/upload",
addRemoveLinks: true
});
this.files = this.dropzone.files;
}
Then use that to create a table using v-for and in each row there would be a category selection dropdown.
<table>
<thead>
<tr>
<th>File Name</th>
<th>File Size</th>
</tr>
</thead>
<tbody>
<tr v-for="file in files">
<td>{{ file.name }}</td>
<td>{{ file.size }}</td>
</tr>
</tbody>
My question then becomes how would you assign a category to each file in the files data property?
In the end I want to send through the file and the category.
From the documentation's list of config options there is the autoProcess option you can use to prevent automatic file upload
If false, files will be added to the queue but the queue will not be processed automatically. This can be useful if you need some additional user input before sending files (or if you want want all files sent at once). If you're ready to send the file simply call myDropzone.processQueue().
By listening to the dropzone's addFile event, you can access the new file and add it to a files array that you can display in your table and later access to add categories (however you want to do that).
this.myDropzone = Dropzone("#my-element", {
url: "/file/upload",
addRemoveLinks: true,
autoProcess: false
});
this.myDropzone.on("addedfile", file => {
this.files.push(file)
});
Finally, you can manually or programmatically trigger the upload with the processQueue function you can call however you'd like, such as on a button click
<button #click="upload">Upload Files</button>
upload() {
this.myDropzone.processQueue();
}
Related
I would like to populate a table with visible rows in Svelte.
My current attempt relies on a {#if variable} test, where the rendered row updates the variable. Unfortunately, the test does not appear to react to changes to the variable. Perhaps this is as designed but the documentation does not appear to address this. Essentially:
<table>
<tbody>
{#each rows as row}
{#if renderIt==true}
<tr use:updateRenderIt>
<td>cell</td>
</tr>
{/if}
{/each}
</tbody>
</table>
I think my understanding of the timing is lacking :(. Perhaps the {#if} block cannot react to each renderIt change. There are quite a few examples of {#if} blocks, but none appear to rely on a variable which is changed within the block.
There is a running example in the Svelte playground. The console divider can be moved vertically to change the viewport dimensions.
If someone knows of a way to achieve this it would be appreciated! I can do it in traditional Javascript, but my Svelte expertise is limited :).
What I'm assuming you want is to have a state on each row when it is visible.
To do so you will need to store some data with your row, so instead of your row being a list of numbers and a single boolean to say if all rows are visible or not, it will be a list of objets that have a property visible:
let rows = [];
for (let i = 0; i < 100; i++) {
rows.push({
index: i,
visible: false,
});
};
Next, to capture when visibility changes on those rows, use Intersection Observer API:
let observer = new IntersectionObserver(
(entries, observer) => {
console.log(entries);
}
);
And use a svelte action to add that observer to elements:
<script>
...
let intersect = (element) => {
observer.observe(element);
};
</script>
<table>
<tbody>
{#each rows as row (row.index)}
<tr
use:intersect>
<td>{row.visible}</td>
</tr>
{/each}
</tbody>
</table>
To pass the intersecting state back to the element throw a custom event on it:
let observer = new IntersectionObserver(
(entries, observer) => {
entries.forEach((entry) => {
entry.target.dispatchEvent(
new CustomEvent("intersect", { detail: entry.isIntersecting })
);
});
}
);
And finally capture that event and modify the state:
<tr use:intersect
on:intersect={(event) => (row.visible = event.detail)} >
<td>{row.visible}</td>
</tr>
To render rows up to how many can fit on screen you could make the defaut state visible: true, and then wrap the element with an {#if row.visible}<tr .... </tr>{/if}. After the first event you would then remove the observer from the element using observer.unobserve by either updating the svelte action or in the observer hook.
I have a partial ... and if I add a link via link.action ... the link is working perfectly fine:
MyPartial.html:
<f:link.action action="show" pageUid="43" pluginName="abc" controller="Abc" extensionName="abc" arguments="{record:1}">ActionLink</f:link.action>
But if I want to add the link.page viewhelper via Javascript to the partial ...
MyPartial.html
<table id="lei_all" width="100%">
<thead>
<tr>
<th>Column01</th>
<th>Column02</th>
</tr>
</thead>
</table>
JS:
var table_all = $('#table_all').DataTable( {
dom: "Blrtip",
ajax: {
url: "/source.php",
type: "POST"
},
serverSide: true,
processing: true,
columns: [
{ data: "column_01",
"render": function ( data, type, row ) {
return '<f:link.action action="show" pageUid="43" pluginName="abc" controller="Abc" extensionName="abc" arguments="{record:1}">'+data+'</f:link.action>';
} },
{ data: "column_02" }
],
...
} );
I'm getting the raw view helper like this:
<tbody>
<tr id=row_1 class="odd" role="row">
<td tabindex="0"><f:link.action action="show" pageUid="43" pluginName="abc" controller="Abc" extensionName="abc" arguments="{record:1}">ActionLink</f:link.action></td>
...
</tr>
</tbody>
How can I add the viewhelper in the above case?
ViewHelpers simply do not work that way. What you are trying is equivalent to calling a PHP function in JavaScript to build a string. The expected result of this is that you will see the Fluid tag output, exactly as you describe.
The only way is to construct your links in PHP and (somehow) transfer them to the JavaScript. Valid ways of doing that includes:
Using data-something properties to carry URLs from HTML to JS
Using an XHR request to create links for a certain purpose
Generating a list of all links indexed by whichever identifier it has in the table, as a JSON or other file in for example typo3temp, then reading this list and using the appropriate link when rendering your table in JS.
Depending on what you need, pick one and implement it so you do not have Fluid code in your JavaScript.
I'm using aurelia's ui-virtualization library to create a table using virtual-repeat and infinite-scroll-next. Html looks something like this:
<table>
<thead>
...
</thead>
<tbody>
<tr virtual-repeat.for="item of items" infinite-scroll-next="getMore">
...
</tr>
</tbody>
</table>
This works great, except I have certain ui components and interactions that update what is in my list array. Once that has be updated, the infinite-scroll-next function (getMore()) is never called. I update something like this:
update() {
let vm = this;
vm.apiService.getData(vm.filterOption)
.then(response => {
vm.items = response.content.items;
});
}
Where filterOptions are changed through the ui and apiService.getData() returns a promise from an http call. The data in the table updates correctly, but the infinite scroll is then broken.
Am I doing something wrong, or is this a bug in ui-virtualization?
Edit:
It appears there are some properties added to the array __array_observer__ and __observers__. Thinking overwriting the whole array and thus removing these properties might be causing the problem, I tried an approach where I just add or remove elements appropriately. This does not work either.
Edit:
It seems to fail if I leave fewer than 7 of the original elements in the array.
I need some advice regarding the usage of jQuery DataTables with Aurelia. Basically I'm running into two problems.
I can't determine the best way to initialize it AFTER the repeat.for binding loop has completed. Apparently that loop is still working even after the attached() lifecycle is fired.
If I use $(myRef).DataTables(data: myArray) method to populate the table, and insert links (<a href-route=... click.delegate=...>) into that table, Aurelia doesn't seem to recognize the links or activate the router.
Problem 1: Here's my attempt to populate the table using Aurelia's binding. Aurelia correctly makes the table, and I can just wait 2-3 seconds and then load DataTables, but that's not the right way. I don't have a definitive event to trigger the loading of the DataTables class because I don't know when repeat.for is completed.
<div class="table-responsive">
<table ref="tblUserList" class="table table-condensed table-hover table-striped" width="100%">
<thead>
<tr>
<th><span t="Username"></span></th>
<th><span t="First_name"></span></th>
<th><span t="Last_name"></span></th>
</tr>
</thead>
<tbody>
<tr repeat.for="record of records">
<td><a route-href="route: user; params.bind: {id: record.user_id}" click.delegate="$parent.select(record)">${record.user_username}</a></td>
<td>${record.p_fname}</td>
<td>${record.p_lname}</td>
</tr>
</tbody>
</table>
</div>
Problem 2: Here's my attempt to populate the table using the jQuery method. DataTables successfully loads the table, but Aurelia doesn't recognize the links or trigger action.
$(this.tblUserList).dataTable({
"paginate": true,
"pageLength": 10,
data: this.records,
columns: [
{ data: 'user_username',
fnCreatedCell: function (nTd, sData, oData, iRow, iCol) {
$(nTd).html("<a route-href='route: user; params.bind: {id:" + oData.user_id + "}' click.delegate='$parent.select(" + oData.user_id + ")'>" + oData.user_username + "</a>");
}
},
{ data: 'p_fname' },
{ data: 'p_lname' }
]
});
Can anyone help me solve any one of the above problems? Or... am I approaching this whole issue the wrong way? Is it better to use the jQuery method to populate, or the Aurelia repeat.for binding loop?
I know this is old, but just in case, if it can help.
When you add DOM elements after binding, they are not aureliazed. You should use the enhance method of TemplatingEngine:
import the TemplatingEngine and inject it:
import {inject, TemplatingEngine} from 'aurelia-framework';
#inject(TemplatingEngine)
In the constructor, initialize the template engine:
constructor(templatingEngine) {
this.templatingEngine = templatingEngine;
}
in Aurelia's attached() method, do your datatable init stuff, and add a class to be able to retrieve your newly created DOM elements:
$(nTd).html("<a class='myclass' ...
Enhance your elements:
$('.myclass').each(function (index, value) {
let el = $(this);
if (!el.hasClass('au-target')) { //can't enhance already aureliazed elm
this.templatingEngine.enhance({element: el[0], bindingContext: this});
//el[0] is important to have DOM and not jQuery object
}
});
Then your binding should work.
Using the first approach (aurelia binding), remove data from the config object and load your data in the activate lifecycle hook:
import 'datatables';
export class UserList {
activate() {
this.records = [...];
}
attached() {
$(this.tblUserList).dataTable();
}
}
I have a couple Javascript functions which concatenates a URL which I set to the variable c. I then try to pass that variable into jQote2:
$.get("emptyReq.tpl", function(tmpl,c) {
$("#reqs").jqoteapp(tmpl, result, c);
});
In emptyReq.tmpl, I'm doing the following:
<tr id="row">
<td name="id" class="id"><%= this.FormattedID %></td>
<td name="name" class="name"><%= this._refObjectName %></td>
<td name="state" class="state"><%= this.ScheduleState %></td>
<td name="owner" class="owner"></td>
</tr>
I've tried a couple of variations (this.c and c) and I've also tried different variables, but I'm not able to get the URL to display correctly.
c is labeled as undefined in the console, and the URL ends up being something like: http://127.0.0.1/xampp/py2/undefined instead of the actual c which is something like https://rally1.rallydev.com/slm/rally.sp#/2735190513d/detail/userstory/4599269614
Is there a way to pass the parameters properly? Or am I supposed to do the concatenation in the .tmpl file itself?
Here is what I've been using as a reference: jQote Reference.
rishimaharaj,
the jqoteapp method's third paramter is used to change the template tag (<% ... %> by default) on a per call basis. If you need to pass additional data to your template you have two options:
Make c a global variable (I wouldn't recommend that, though)
Copy c's value to the data parameter (recommended):
Please be aware that the copying needs to take into account of what type your
templating data is, i.e. a single object is handled different from an array of
objects!
$.get("emptyReq.tpl", function(tmpl,c) {
var data;
// 'result' seems to be a global var, thus making a copy is a good idea.
// Copying needs to take into account the type of 'result'
if ( Object.prototype.toString(result) === '[object Array]' ) {
data = result.slice(0);
} else {
data = [$.extend({}, result)];
}
// Now it is safe to add 'c' to the wrapping array. This way
// we won't override any homonymous property
data.c = c;
// Call the processing with our local copy
$("#reqs").jqoteapp(tmpl, data);
});
Once you've changed this, you will be able to access c through the templating
lamda's inherent property data:
<tr id="row">
... <a href="<%= data.c %>"><%= this.FormattedID ...
</tr>
Regards,
aefxx