I'm using tom-select on my django form. On the form I also make a reset button to clear all input fields. All input values are cleared when I click the button, except the one using tom-select.
form.py
class ItemInputForm(ModelForm):
def __init__(self, *args, **kwargs):
super(ItemInputForm, self).__init__(*args, **kwargs)
self.helper = FormHelper(self)
self.helper.layout = Layout(
Row(
....
Column('item', css_class = 'col-md-4'),
css_class = 'row'
),
....
Div(
HTML('<button type="submit" class="btn btn-danger col-md-4 me-4"><i class="fa-solid fa-print"></i> Print</button>'),
HTML('<button type="reset" class="btn btn-warning col-md-4"><i class="fa-solid fa-rotate-left"></i> Reset</button>'),
css_class = 'text-center'
),
....
tom-select on the template
$(document).ready(function()
{
var item_select = new TomSelect("#id_item",{
create: false,
placeholder: 'Search',
valueField: 'value',
searchField: 'text',
maxItems: 1,
closeAfterSelect: true,
render: {
option: function(data, escape) {
return '<div>' + '<span class="text">' + escape(data.text) + '</span>' + '<span class="value">' + escape(data.value) + '</span>' + '</div>';
},
item: function(data, escape) {
return '<div title="' + escape(data.value) + '">' + escape(data.text) + '</div>';
},
},
});
item_select.clear();
When I refresh the page, the input field is clear because of item_select.clear(), but it didn't work if I want to clear with reset button. How to clear the tom-select input with reset button?
I was confronted to the same issue, and here is my solution.
I enable tom-select for each HTML element having the tom-select-enabled class.
I use the tomselected class to fetch all tom-select enabled elements of a form on reset, and call the tomselect.clear() method.
document.addEventListener('DOMContentLoaded', function() {
// Select all elements having the class 'tom-select-enabled', and enable TomSelect for these elements.
document
.querySelectorAll(".tom-select-enabled")
.forEach((tomSelectElement) => {
console.log(`Enabling tom-select for #${tomSelectElement.id}`);
var tomSelectItem = new TomSelect(tomSelectElement, {
plugins: {
clear_button: { title: "Vider" }
},
create: false,
persist: false
});
});
// Clear all TomSelect instances of forms on reset.
document.querySelectorAll("form").forEach((formElement) => {
formElement.addEventListener("reset", (event) => {
event.target
.querySelectorAll(".tomselected")
.forEach((tomselectedElement) => {
tomselectedElement.tomselect.clear();
});
});
});
});
As far as I could find, the reset event is not triggered for the element once TomSelect is instantiated.
Another issue is that the clear() method visually empty the tom-select field, but if the initial select field has a selected="selected" <option>, it set the select value to its selected option default.
If filed two issues on the subject:
Tom Select enabled field does not react to form reset events #544.
clear() method empty the visible tom-select field, but set the select field to the default selected option #545.
I've found some tips on how to clean my code in How to clear existing (dynamically created) instances of Tom-Select #170.
Related
I'm a hobbyist on my first project. In a form, oranizers can select multiple events in a collection select. I want these events to be available as choices in an array field checkbox collection further down in the same form.
First, organizer selects the events:
<%= f.input :events, collection: #organizer.events.order(:start_time).reverse, label_method: :event_name_and_date, input_html: {multiple: true, id: "event_select"} %>
Then, this checkbox collection field (and others like it in the form) should dynamically update with the previously selected events as options, so the ids of the checked off events get sent in the param array.
<%= f.input :events_to_include_in_event_pass_1, :collection => ["(previously selected events", "etc"], :as => :check_boxes, include_hidden: false, :input_html => {:multiple => true, id: "event_pass_select"} %>
I've got an ajax:
$('#event_select').on('change', function(){
var grab_events = $('#event_select').val();
var hpeData = '{"hpe": "' + grab_events + '"}';
$.ajax({
type: 'post',
url:'/events/get_the_e',
dataType:'json',
contentType:'application/json',
data: hpeData,
success:function (data) {
... $("document.forms["eventForm"]["events_to_include_in_event_pass_1"].collection_value(?)").update_with('data.hpe.each.event_name_... and_id_somehow_gets_added')
}
});
}
which brings back the instances selected in the first collection field, but I don't know how to dynamcially change #event_pass_select collection with these instances. ... is this even possible? Or is there some general better way to set something like this up?
Don't need an ajax call -- that's taking the data from the browser, sending it back to the server, then updating the browser.
A little jQuery will do the trick. Read through the selected options and use them to fill the desired input. Something like this...
$('#event_select').on('change', function(){
$("#event_pass_select").empty();
$("#event_select option:selected").each(function() {
var val = $(this).val();
var text = $(this).html();
$("#event_pass_select").append( $("<option>")
.val(val)
.html(text)
);
});
});
Change '#event_pass_select' to the appropriate control id on your form.
I didn't realize the input_html was in fact working, it just applied the id to each checkbox, instead of the whole input. I figured that out by clicking 'edit as html' in ctrl c. I also saw all the html that makes up each checkbox, and thought I would try putting all that in there, instead of just option, and it worked. These are probably a result of simpleform? I appreciate the help dbugger.
$('#event_select').on('change', function(){
var asdf = 1;
$("#event_select option:selected").each(function() {
var val = $(this).val();
var text = $(this).html();
if (asdf === 1) {
$(".festival_multipass_ticket_1_hpe span").empty();
$(".festival_multipass_ticket_1_hpe").append( $('<span class="checkbox"><label for="festival_multipass_ticket_1_hpe_' + asdf + '"><input class="check_boxes optional" type="checkbox" value="' + val + '" name="festival[multipass_ticket_1_hpe][]">' + text + '</label></span>')
);
} else {
$(".festival_multipass_ticket_1_hpe").append( $('<span class="checkbox"><label for="festival_multipass_ticket_1_hpe_' + asdf + '"><input class="check_boxes optional" type="checkbox" value="' + val + '" name="festival[multipass_ticket_1_hpe][]">' + text + '</label></span>')
);
}
asdf += 1;
});
I am having a dropdown list on the header of data table. The list has multiple checkbox and I want to call an event when the checkbox is checked or unchecked.
During debug, breakpoint is not hitting the checkbox click event. Please let me know how to implement for checkbox click/change event in this scenario.
This is because #chk_select_abst is not rendered at the time of DOM ready when you are binding that event.
For binding events on dynamically added DOMs, you can bind or delegate the event somewhere on its parent DOM node which you are sure will be there on page load and will NEVER be removed/replaced dynamically. Behind the scenes, this make use of event bubbling or event propagation. Check out this link for more info about bubbling.
A safe bet is to use the parent node as body. But, you can and should use a lower parent node (in this case #ul_AbandonedStates) for performance gain.
Documentation for jQuery event delegation.
var json = {
abandonState: [{
Name: 'name 1',
Value: 'value 1'
}, {
Name: 'name 2',
Value: 'value 2'
}]
}
function addCheckBox() {
if (json) {
if (json.abandonState) {
var abandonedStates = json.abandonState;
var li = $('<li>');
var select = $("<label><input id='chk_select_abst' type='checkbox' class='abandonstatecheckclass' value='-1' name='Select All' /> Select All</label>");
var res = li.append(select);
$('#ul_AbandonedStates').append(res);
$.each(abandonedStates, function(index, item) {
var li = $('<li>');
var chk = $("<label><input id='chk_" + item.Value + "' type='checkbox' class='abandoncheckclass' value='" + item.Value + "' name='" + item.Name + "' />" + item.Name + "</label>");
var res = li.append(chk);
$('#ul_AbandonedStates').append(res);
});
var li = $('<li>');
var btn = $('<button id="ul_AbandonedStates_ok" class="btn btn- primary btn- xs" type="button" value="OK">OK</button>');
var res = li.append(btn);
$('#ul_AbandonedStates').append(res);
}
}
}
$(document).ready(function() {
//change here
$("#ul_AbandonedStates").on("click", "#chk_select_abst", function() {
$("#ul_AbandonedStates input:checkbox").prop('checked', $(this).prop('checked'));
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table>
<th align="center" width="13%" style="position:relative;" index=6 name="abandonedState">
Abandon State
<div class="down-arrow-wrapper">
<ul class="checkbox-list" id="ul_AbandonedStates"></ul>
</div>
<th>
</table>
<button class="add" onclick="addCheckBox()">Add List</button>
So I've wrote a script that gives the user the option to add more than one image to a form. If the user chooses to add more than one image, they click the 'Add another image' button, and another file field is added.
When the new file field is added, the id given to that field is unique. The first field is statically set to "1". If the user clicks 'Add another image', the second field is given the id of "2", then another would be "3" etc etc. This has been working successfully.
Note:
I'm not giving them the option to remove the first file field at all.
The issue:
Due to the fact that I want to check that each file field has actually got a file ready for upload, I've decided to add a 'Remove this image' next to each field when the 'Add another image' button is selected.
Ideally, when the user clicks the 'Remove this image' button, the id of the fields after that field are all changed by -1.
EG: The user has inserted five additional file fields using the 'Add another image' button, and they have clicked on the 'Remove this image' button next to the file field with the id of '3', meaning that '4', '5' and '6' should become '3', '4' and '5'.
Edit:
Current functionality:
The id's are being subtracted accordingly, however when a new field is added, it is continuing from the previous count. EG: If file fields '5' and '6' are removed, then another one is added, it is given the id of '7'.
If any of you can help me with this dilemma it'd be much appreciated. It's frying my head a little.
Thanks in advance, Rich
Here are my efforts thus far:
$(document).ready(function() {
var count = 2;
$('#addImage').click(function(){
var countNew = count++;
$('#newsFormContainer #addImage').before( $('<div id="added"><br /><label for="' + countNew + '">Image ' + countNew + '</label class="strong" ><br /><input type="file" class="file" name="' + countNew + '" id="' + countNew + '" accept=".png"></div>'));
$('#newsFormContainer #addImage').before( $('<button id="' + countNew + '" class="file" onclick="return false;">Remove this image</button>'));
$('button.file').click(function(){
var grabClass = document.querySelectorAll('[class^=file]');
console.log(grabClass)
$(grabClass).attr('id', function(index){
return index + 1;
});
$(this).prev('#added').remove();
$(this).remove();
});
var inputs = document.querySelectorAll('[file^=file]').length;
document.getElementById('cnt').value = inputs;
});
});
Try Running this Code; may be this solves your problem
$('#add-item').on('click', function() {
var indexOfLastItem = parseInt($('ul>li:last').attr('data-index'));
if(!indexOfLastItem){
indexOfLastItem = 0;
}
indexOfLastItem += 1;
$('ul').append('<li data-index="' + indexOfLastItem + '">Item ' + indexOfLastItem + '<button>Remove Image</button></li>')
});
/**
* Dynamically assigning event handler
* Other wise it will not work for 'Remove' buttons added in runtime
*
*/
$(document).on('click', 'li> button', function() {
var indexOfLi = $(this).parent().attr('data-index');
var $currentLi = $(this).parents('li');
var $itemsAfterCurrent = $currentLi.nextAll();
console.log($itemsAfterCurrent);
rearrangeItems($itemsAfterCurrent);
$currentLi.hide('slow', function() {
$(this).remove();
})
})
function rearrangeItems($itemsAfterCurrent) {
$itemsAfterCurrent.each(function() {
var index = $(this).attr('data-index');
index = parseInt(index) - 1;
console.log(index);
$(this).attr('data-index', index);
$(this).html('Item ' + index + '<button>Remove Image</button>');
});
}
li{
margin: 5px;
}
li>button{
margin: 0 3px;
cursor: pointer;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul>
<li data-index="1">Item 1 <button>Remove Image</button></li>
<li data-index="2">Item 2<button>Remove Image</button></li>
<li data-index="3">Item 3<button>Remove Image</button></li>
<li data-index="4">Item 4<button>Remove Image</button></li>
<li data-index="5">Item 5<button>Remove Image</button></li>
<li data-index="6">Item 6<button>Remove Image</button></li>
</ul>
<button id="add-item">Add Image</button>
You need a loop that checks the id of the deleted picture and the for all pictures with an id greater then the picture being deleted subtract 1 from the value of their id.
I stumbled upon this article on how to build a click to edit feature for a form. The author states:
What about if you wanted input type="date" or even a select? This
is where you could add some extra attribute names to the directive’s
scope, like fieldType, and then change some elements in the template
based on that value. Or for full customisation, you could even turn
off replace: true and add a compile function that wraps the necessary
click to edit markup around any existing content in the page.
While looking through the code I cannot seem to wrap my head around how I could manipulate the template in such a way that I could make it apply to any angular component, let alone how I can make it apply to a drop down list. Code from article below:
app.directive("clickToEdit", function() {
var editorTemplate = '<div class="click-to-edit">' +
'<div ng-hide="view.editorEnabled">' +
'{{value}} ' +
'<a ng-click="enableEditor()">Edit</a>' +
'</div>' +
'<div ng-show="view.editorEnabled">' +
'<input ng-model="view.editableValue">' +
'Save' +
' or ' +
'<a ng-click="disableEditor()">cancel</a>.' +
'</div>' +
'</div>';
return {
restrict: "A",
replace: true,
template: editorTemplate,
scope: {
value: "=clickToEdit",
},
controller: function($scope) {
$scope.view = {
editableValue: $scope.value,
editorEnabled: false
};
$scope.enableEditor = function() {
$scope.view.editorEnabled = true;
$scope.view.editableValue = $scope.value;
};
$scope.disableEditor = function() {
$scope.view.editorEnabled = false;
};
$scope.save = function() {
$scope.value = $scope.view.editableValue;
$scope.disableEditor();
};
}
};
});
My question is, how can we extend the above code to allow for drop down edits? That is being able to change to the values that get selected.
One approach you might consider is using template: function(tElement,tAttrs ).
This would allow you to return appropriate template based on attributes.
app.directive("clickToEdit", function() {
return {
/* pseudo example*/
template: function(tElement,tAttrs ){
switch( tAttrs.type){
case 'text':
return '<input type="text"/>';
break;
}
},....
This is outlined in the $compile docs
I am trying to put a button in the cells of one of the columns and do something when it's clicked.
For example I add these lines to the SlickGrid example 1 (http://mleibman.github.io/SlickGrid/examples/example1-simple.html)
First to the column array I add:
{id: "Report", name: "Report", field: "Report", width: 40, sortable: true, formatter:reportFormatter}
then I add:
function reportFormatter(row, cell, value, columnDef, dataContext) {
return "<input type='button' value='show' id='reportBtn'/>";
}
$('#reportBtn').click(function() {
alert("hello");
});
The buttons appear in the cells but the click event is not being called !
I must be doing something wrong but can't for the life of me figure it out
can anyone help ?
Thanks!
slick.formatters.js
...
"btnForm": buttonsFormatter // add Slick.Formatters
..
function buttonsFormatter(row, cell, value, columnDef, dataContext) {
return "<input type='button' value='"+value+"' id='btnForm' value2='"+row+"' value3='"+cell+"' onClick='fnBtnClick(this);'/>";
}
add your html Script
function fnBtnClick( objBtn ){
alert( "row::[" + objBtn.value2 + "]\n\ncell::[" + objBtn.value3 + "]" );
}
you should use the grid events not button event like below ,
will call the onclick event of the grid ,
check if the clicked field is your button one
do your action
grid.onClick.subscribe(function (e, args) {
//check if your button was clicked
if ($(e.target).hasClass("btn")) {
var item = dataView.getItem(args.row);
///do your action
}
});
Use the precompiled template slick grid example. Add the property eg. ImageTrial, and in the data structure fill the property with the dynamic input button.
<script type=" " id="testtemplate">
<div class="test">
<b><%=ImageTrial%></b>
<b><%=ImageTrial2%></b>
</div>
dataForCell["ImageTrial"] = "<button type=\"button\" onclick=\"alert('a " + 1 + "')\">s</button>";
dataForCell["ImageTrial2"] = "<button type=\"button\" onclick=\"alert('b " + 2 + "')\">b</button>";
Good Luck