I have a form with different fields and with input type="file". I use fileupload jQuery library.
Select file
Call
$('#some_id').fileupload().fileupload(
'send',
{
files: file,
url: widget.options.saveVideoUrl,
}
).success(
//...
(first fileupload called for init)
Try again to select file. Got: No files selected, clear console, etc..
Upd.1
The problem appear in E-commerce framework Magento2 in admin area.
The described form appear in such entity like 'slide-out panel'. It means that there is div block and this block wrapped in aside block using javascript.
<button onclick="jQuery('#new').modal('openModal')" .... >
<span>New</span>
</button>
Here is demo example:
Admin URL: https://iwdagency.com/magento2/admin
Username: admin
Password: admin123
Open Products / Catalog / select any product / click on New category
You should see following panel:
On such panel I've added by php constructor fields:
<div class="admin__field field field-new_video_screenshot " data-ui-id="product-tabs-tab-google-experiment-fieldset-element-form-field-new-video-screenshot">
<label class="label admin__field-label" for="..." data-ui-id="product-tabs-tab-google-experiment-fieldset-element-file-image-label"><span>Preview Image</span></label>
<div class="admin__field-control control">
<input id="...." name="image" data-ui-id="product-tabs-tab-google-experiment-fieldset-element-file-image" value="" title="Preview Image" type="file">
</div>
</div>
Script:
define([
'jquery',
'jquery/ui',
'Magento_Ui/js/modal/modal',
'mage/translate',
'mage/backend/tree-suggest',
'mage/backend/validation'
], function ($) {
'use strict';
$.widget('mage.newDialog', {
_create: function () {
var widget = this;
var newVideoForm = $('#new');
this.element.modal({
type: 'slide',
modalClass: 'mage-new-dialog form-inline',
title: $.mage.__('Create'),
buttons: [{
text: $.mage.__('Create'),
class: 'action-primary',
click: function (e) {
var file = $('#new_screenshot').get(0).files[0];
var result = $('#new_screenshot').fileupload().fileupload(
'send',
{
files: file,
url: widget.options.saveUrl,
}
).success(
function(result, textStatus, jqXHR)
{
var data = JSON.parse(result);
data['url'] = $('#new_url').val();
data['name'] = $('#new_name').val();
data['description'] = $('#new_description').val();
$('#media_gallery_content').trigger('addItem', data);
$('#new').modal('closeModal')
}
);
}
}],
});
}
});
return $.mage.newDialog;
});
I found the problem.
In my case the problem appear after initialization fileUpload library.
When I selected input:file, the library wasn't initialized (read as infected). When I pressed the button, initialization ran and any operations with this input become unavailable.
Solution is following: clone our input before it become infected, than do our operations and at the end replace existing infected input with its healthy copy, created before.
Related
I need some help. How can I add new values in code to the list if I use a plugin from jquery. I wrote this code, but the list is empty, although the values are passed to the view. This is probably due to the fact that I am referring to the id of the div tag, but the plugin did not work differently. Help please
<html>
<main>
<form action="#">
<div class="form-group col-xs-12 col-sm-4" id="example-2"> </div>
</form>
</main>
<script>
$('#example-2').selectivity({
items: ['Amsterdam', 'Antwerp'],
multiple: true,
placeholder: 'Type to search a city'
});
function addOption() {
var ul = document.getElementById("#example-2");
for (var item in #ViewBag.List)
{
var value = item;
}
var newOption = new Option(value, value);
ul.options[ul.options.length] = newOption;
}
</script>
</html>
result of code from answer 1
The documentation of the selectivity library covers how to add new options to the dropdown.
The main issue you have is that the output from #ViewBag.List won't be in a format that JS can understand. I would suggest formatting it as JSON before outputting it to the page, then the JS can access this as a standard object, though which you can loop.
// initialisation
$('#example-2').selectivity({
items: ['Amsterdam', 'Antwerp'],
multiple: true,
placeholder: 'Type to search a city'
});
// add options, somewhere else in your codebase...
const $list = $('#example-2')
const options = #Html.Raw(Json.Encode(ViewBag.List));
options.forEach((option, i) => {
$list.selectivity('add', { id: i, text: option })
});
Note that for this to work the JS code which reads from the ViewBag needs to be placed somewhere the C# code will be executed, ie. in a .cshtml file, not in a .js file.
So I am building a mailmerge tool, and it works fine.
Testing the trigger with a hard coded input works fine:
function test(){
sendEmails("TEST MAILMERGE FROM DRAFT")
}
It also works fine if I prompt an input box (relevant section of the code shown).
function sendEmails(subjectLine,sheet=SpreadsheetApp.getActiveSheet()) {
if (!subjectLine) {
subjectLine = Browser.inputBox(
"Mail Merge",
"Type or copy/paste the subject line of the Gmail " +
"draft message you would like to use:",
Browser.Buttons.OK_CANCEL
);
if (subjectLine === "cancel" || subjectLine == "") {
// if no subject line finish up
return;
}
}
However, trying to be smarty pants and have the menu dynamically populated with Subject lines like this:
function onOpen() {
// get the UI for the Spreadsheet
const ui = SpreadsheetApp.getUi();
// add the menu
const menu = ui.createMenu("TEST");
// get the drafts from Gmail
let drafts = GmailApp.getDraftMessages();
// for each draft, create a new menu item
drafts.forEach((draft) => {
// add the drafts to be triggered using the following: addItem(caption: string, functionName: string)
menu
.addItem(
draft.getSubject().toString(),
'sendEmails("' + draft.getSubject().toString() + '")'
)
.addToUi();
});
}
However, this doesn't work. It comes up with the following error:
Error Script function not found: sendEmails(TEST MAILMERGE FROM DRAFT)
Which to me looks like it should work. As the testing trigger that is hardcoded above works.
Am I being daft here? As far as I can see, this should work? But it's not.
When / if I get it working, I will put a check in to account for 'trash' drafts that don't have a subject. Just trying to get it to actually work for now though.
Menu.addItem(caption, functionName)
Parameters:
caption: The label for the menu item, with only the first word capitalized.
functionName: The name of the function to invoke when the user selects the item. You can use functions from included libraries, such as Library.libFunction1.
Menu.addItem() expects a function name without arguments. It doesn't allow to pass arguments in the function.
Workaround:
Based on my understanding, your goal is to have a different menu item that could send emails on each draft messages available in your email account.
You might want to consider using Custom dialogs or Custom sidebars where in you can select your draft message subject that you want to pass as argument when you call your sendEmails() function. You can refer to the sample code as reference.
Sample Code:
(Code.gs)
function onOpen() {
// get the UI for the Spreadsheet
const ui = SpreadsheetApp.getUi();
// add the menu
const menu = ui.createMenu("TEST")
.addItem('Send Email', 'selectDraft')
.addToUi();
}
function selectDraft() {
var html = HtmlService.createHtmlOutputFromFile('draft');
SpreadsheetApp.getUi() // Or DocumentApp or SlidesApp or FormApp.
.showModalDialog(html, 'Select Draft Message');
}
function getDraftSubject(){
// get the drafts from Gmail
let drafts = GmailApp.getDraftMessages();
var subjects = [];
// for each draft, create a new menu item
drafts.forEach((draft) => {
subjects.push(draft.getSubject().toString());
});
Logger.log(subjects);
return subjects;
}
function sendEmails(subjectLine,sheet=SpreadsheetApp.getActiveSheet()) {
Logger.log(subjectLine);
}
(draft.html)
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<h2>Select Draft Subject</h2>
<form id="myForm" onsubmit="handleFormSubmit()">
<div class="form-group">
<label for="subject">Draft Subject</label>
<select class="form-control form-control-sm" id="subject" name="subject" required>
<option value="" selected>Choose...</option>
</select>
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
<script>
google.script.run.withSuccessHandler(function(subj) {
let select = document.getElementById("subject");
subj.forEach(function(e, i) {
let option = document.createElement("option");
option.value = e;
option.text = e;
select.appendChild(option);
});
}).getDraftSubject();
function handleFormSubmit() {
var value = document.getElementById("subject").value;
google.script.run.sendEmails(value);
document.getElementById("myForm").reset();
}
</script>
</body>
What it does?
Create a custom menu that will show a dialog box based on the draft.html
In draft.html, We used google.script.run.withSuccessHandler(function) to call getDraftSubject() in our server side (apps script) which returned an array of draft message subjects. We then update the form's select class and add options based on each draft message subjects obtained.
When the form was submitted, it will call handleFormSubmit(), we get the selected draft message subject and pass that value using google.script.run.myFunction(...) (any server-side function).
google.script.run.sendEmails(value);
Output:
In certain cases, usually after values have been cached from an initial search, I cannot get the mdb_autocomplete drop down to close on a single click. I often have to double click on my selection to get it to close. I am dynamically populating the values in the drop down via an Ajax call to a service method via and controller action method that searches the active directory for the first 30 name values. No call back occurs until a user enters at least 3 values into the mdb_autocomplete selection box. The callback and population of the drop down is working very well, but the click event following the selection of a value often will not close the dropdown. Additionally, we are being forced to use mdb boostrap over the normal bootstrap library. I have included the view, service, and typescript code that is being used to generate and populate the drop down.
View:
<div class="form-group">
<label class="font-weight-bold" for="RequestorSearchInput">Requestor</label>
<input type="text" id="RequestorSearchInput" name="RequestorSearchInput" class="form-control mdb-autocomplete" />
<span id="loading_data_icon"></span>
</div>
Service Method:
public List<string> GetRequestor(string aRequestor)
{
IEnumerable<Dictionary<string, string>> requestorNames;
using (ActiveDirectoryService service = new ActiveDirectoryService(<LDAP Domain Name>))
{
string[] propertiesToLoad = new string[] { "displayName" };
//requestorNames = service.SearchByPartialUsername(aRequestor, propertiesToLoad).Take(30).Union(service.SearchBySurname(aRequestor, propertiesToLoad).Take(30));
requestorNames = service.SearchBySurname(aRequestor, propertiesToLoad).Take(30);
}
return requestorNames.SelectMany(x => x.Values).Where(y => y.IndexOf(",", StringComparison.Ordinal) >= 0).Distinct().ToList();
}
TypeScript:
private handleRequestorSearch() {
let options: string[] = new Array();
// #ts-ignore
let searchval = $("#RequestorSearchInput").val().length;
if (searchval >= 3) {
$.ajax({
url: main.getControllerHREF("GetRequestor", "Search"),
method: "POST",
data: {
requestor: $("#RequestorSearchInput").val()
},
async: false,
dataType: "json",
success: function (names) {
$.each(names, function () {
options.push(this);
});
// #ts-ignore
$("#RequestorSearchInput").mdb_autocomplete({
data: options
}).select(function () {
$("#RequestorSearchInput").focus;
});
}
});
}
}
I'm using https://www.npmjs.com/package/ng2-uploader package for file upload in angular, everything works fine for single input. But I want more than one input with different options and urls like this
<input type="file"
ngFileSelect
[options]="options1"
(onUpload)="handleUpload($event)"
(beforeUpload)="beforeUpload($event)">
<input type="file"
ngFileSelect
[options]="options2"
(onUpload)="handleUpload($event)"
(beforeUpload)="beforeUpload($event)">
Configuration for file upload I'm trying to do is
this.options1 = {
url: 'url for first input'
fieldName: 'first input field name',
method: 'PUT'
};
this.options2 = {
url: 'url for second input'
fieldName: 'second input field name',
method: 'PUT'
};
handleUpload(data): void {
if (data && data.response) {
data = JSON.parse(data.response);
this.uploadFile = data;
//code
}
}
fileOverBase(e:any):void {
this.hasBaseDropZoneOver = e;
}
beforeUpload(uploadingFile): void {
if (uploadingFile.size > this.sizeLimit) {
uploadingFile.setAbort();
alert('File is too large');
}
}
This results in always picking up the latter options i.e 'options2' and 'options1' donot have any effect. How do I implement this?
I had similar issue.
And in my case, I had duplicates of input's ids and label's for picked the wrong one.
By the way ng2-uploader was renamed to ngx-uploader. Recently its api changed a lot, but there was versions compatible with ng2-uploader, with some bugs fixed.
I am using the jQuery X-Editable edit-in-place library on a field and the JavaScript Marked Markdown Parser library to try and convert Markdown strings into HTML.
The goal is to show HTL and when it turns into a textarea edit field, to then how the Markdown. The Markdown will be what is saved and loaded from the backend in the live app.
I have setup a JSFiddle demo for this functionality...
http://jsfiddle.net/jasondavis/bfrrzz8h/
If you view the demo and click to edit the Description text and paste in this Markdown string # Marked in browser\n\nRendered by **marked** and click save, it will then alert you the parsed markdown to HTML string. THe problem is it does not update the DOM to show that new HTML string.
Any help in this please?
Marked library - https://github.com/chjj/marked
X-Editable library - https://github.com/vitalets/x-editable/
JavaScript from my demo
$('#task-description-modal').editable({
type: 'textarea', // text|textarea|select|date|checklist
url: '/updatetask',
pk: 123,
toggle: 'click', // click|dblclick|mouseenter|manual
inputclass: 'task_description resizable',
highlight: '#F1FFE7',
mode: 'inline', // inline | popup
placement: 'top',
title: 'Enter Task Description',
validate: function(value) {
if ($.trim(value) === '') {
return 'Task Description is Required';
}
},
params: function(params) {
//Addition params in addition to the default: pk, name, value
return params;
},
success: function(response, newValue) {
if (!response.success) return response.msg;
}
});
$('#task-description-modal').on('save', function(e, params) {
// Parse Description Markdown into HTML
var markdownDescription = marked(params.newValue);
alert(markdownDescription);
$('#task-description-modal').html(markdownDescription);
//$('#task-description-modal').html('test');
});
//ajax emulation. Type "err" to see error message
$.mockjax({
url: '/updatetask',
responseTime: 400,
response: function(settings) {
if(settings.data.value == 'err') {
this.status = 500;
this.responseText = 'Validation error!';
} else {
this.responseText = '';
}
}
});
You're injecting your compiled HTML into the element you're using to get markdown input. This is simply setting yourself up for failure: have two elements, one for markdown text, and one to show the result, and switch between the two.
For instance, the following code already makes things work fine:
HTML:
<div style="margin: 50px">
<span id="task-description-modal">Task Description text</span>
<div id="processed"></div>
</div>
JS:
$('#task-description-modal').on('save', function(e, params) {
var markdownDescription = marked(params.newValue);
$('#processed').html(markdownDescription);
});
You just need to make sure to only show the element you intend to be shown depending on what the user has just done. Hidden #task-description-modal until the user clicks on #processed, at which point you hide #processed and force .focus() on #task-description-modal? Perfect.