I am using Algolia and instantsearch.js for one of my projects.
I managed to get the custom searchbox to work. Inside JS I create an input field and style it to look nice:
// searchbox design
var searchField = '<div class="input-search">';
searchField += '<i class="input-search-icon wb-search" aria-hidden="true"></i>';
searchField += '<input type="text" class="form-control" id="customerSearch" name="search" placeholder="Search for customer..">';
searchField += '<span id="custom-clear-all-container"></span>';
searchField += '</div>';
// custom `renderFn` to render the custom SearchBox widget
function renderFnSB(SearchBoxRenderingOptions, isFirstRendering) {
if (isFirstRendering) {
SearchBoxRenderingOptions.widgetParams.containerNode.html(searchField);
SearchBoxRenderingOptions.widgetParams.containerNode
.find('input')
.on('keyup', function() {
SearchBoxRenderingOptions.refine($(this).val());
});
SearchBoxRenderingOptions.widgetParams.containerNode
.find('input')
.val(SearchBoxRenderingOptions.query);
}
}
// connect `renderFn` to SearchBox logic
var customSearchBox = instantsearch.connectors.connectSearchBox(renderFnSB);
// mount widget on the page
search.addWidget(
customSearchBox({
containerNode: $('#custom-searchbox')
})
);
The code above is almost identical to the code example in Algolia's documentation. I just added a "div" in DOM with id="custom-searchbox". This works just fine.
Then I try to create a custom clear all button and append it to:
<span id="custom-clear-all-container"></span>
inside searchbox. Again I use an almost identical code as Algolia's documentation:
function renderFnCA(ClearAllRenderingOptions, isFirstRendering) {
var containerNode = ClearAllRenderingOptions.widgetParams.containerNode;
if (isFirstRendering) {
var markup = $('<button id="custom-clear-all" type="button" class="input-search-close icon wb-close" aria-label="Close"></button>');
containerNode.append(markup);
markup.on('click', function(event) {
event.preventDefault();
ClearAllRenderingOptions.refine();
})
}
var clearAllCTA = containerNode.find('#custom-clear-all');
clearAllCTA.attr('disabled', !ClearAllRenderingOptions.hasRefinements)
};
// connect `renderFn` to ClearAll logic
var customClearAllWidget = instantsearch.connectors.connectClearAll(renderFnCA);
// mount widget on the page
search.addWidget(
customClearAllWidget({
containerNode: $('#custom-clear-all-container'),
clearsQuery: true
})
);
When I run the code, everything is working but I don't see the clearAll button (in my case is an X icon).
If I insert the:
<span id="custom-clear-all-container"></span>
directly into HTML and remove it from JS, then it works perfectly.
I don't know what is going wrong. By the way, the code to add clearAll is after the code for adding the searchbox. So, the searchbox DOM element is already placed in DOM when we are trying to append clearAll button.
Any ideas why this is happening?
Thanks in advance!
You're probably going to want to leave the button in the dom and instead of completely removing it $('#custom-clear-all').hide() it instead.
The algolia search widget is probably looking for the button all the time and when its not found in dom it doesn't run
Related
I'm new to coding in general, but I have a question regarding how to capture the value from Google Maps Searchbox to try and then dynamically create a div tag that will display a row with value of whatever was entered into the Searchbox.
I have tried creating an .onclick() event but proved useless since the Searchbox doesn't require a submit button to find results.
// Adding event listener for when user clicks the add-bttn
$("#search").on("click", function() {
// variable for using the search functionality and adding it to the itinerary for the first day
var itineraryInput = $("#form-control").val();
console.log(itineraryInput);
})
.then(function() {
var row = $("<div>");
row.addClass("attraction");
row.append("<p>" + itineraryInput + "</p>");
$("#trans_first").prepend(row);
});
the error that I get in the console is:
Uncaught TypeError: $(...).on(...).then is not a function.
I simply want to grab the value from the Searchbox but have no idea about getting that result.
You don't need to use then, you can just put your function inside the click event listener:
// Adding event listener for when user clicks the add-bttn
$("#search").on("click", function() {
// variable for using the search functionality and adding it to the itinerary for the first day
var itineraryInput = $("#form-control").val();
console.log(itineraryInput);
var row = $("<div>");
row.addClass("attraction");
row.append("<p>" + itineraryInput + "</p>");
$("#trans_first").prepend(row);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<label> Search
<input id="form-control" >
</label>
<button id="search">Search </button>
<div id="trans_first">
</div>
So I have a list of items with anchor a that successfully listen to the following event:
$('body[data-link="media"] #media_content a').on('click',function(e){
e.preventDefault();
var page = $('.page.active a')[0].innerHTML;
var date = $('.year_sorting .filter_years').val();
var id = $(e.currentTarget).data('media');
window.location.href = 'http://'+basePath+'media/content/'+id+'?date='+date+'&page='+page;
})
However in the same page, there is a filter allowing the user to change the year filter and once changed, the following execute and append a list of items that has the exact same layout as the a above $('body[data-link="media"] #media_content a'), which supposes to listen to the above event as well. the filter event is below:
$('.activity.filter_years').on('change',function(){
$('.pagination_ul').remove();
r_year = $(this).val();
$.get("media/getActivity",{type:'0',key:r_year}).done(function(d){
if(d.length>0){
$('#media_content').html('');
var ul = '<ul class="ap pagination-sm pagination_ul"></ul>';
$('.pagination_menu').append(ul);
for(var i=0;i<d.length;i++){
var p = ['',''];
if(!d[i].event_period){
p = ['style="color:#8A8A8A;"','style="color:#C7C7C7;"'];
}
if(locale=='en'){
var event = $('<div class="div_media_content_f2 '+d[i].pagination+' pagination-tr"> <div class="div_media_content_f2_3"> <span class="font12_bold">'+d[i].event_date+'</span> <div>'+d[i].event_title+'</div></div></div>')
}else if(locale=='hk'){
var event = $('<div class="div_media_content_f2 '+d[i].pagination+' pagination-tr"> <div class="div_media_content_f2_3"> <span class="font12_bold">'+d[i].event_date+'</span> <div>'+d[i].event_title_zh+'</div></div></div>')
}else {
var event = $('<div class="div_media_content_f2 '+d[i].pagination+' pagination-tr"> <div class="div_media_content_f2_3"> <span class="font12_bold">'+d[i].event_date+'</span> <div>'+d[i].event_title_cn+'</div></div></div>')
}
$('#media_content').append(event);
}
pagination('.pagination_ul','.pagination-tr',Math.ceil(d.length/20),false);
}else{
$('#div_news_content_right').html('').append('<div class="not_available">No content available</div>');
}
})
})
in which you can see the list of items are being appended into the layout by JS. However, even with the same layout $('body[data-link="media"] #media_content a'), such appended list of items do not listen to the onclick event. the above js codes are together in a separate js file apart from the html file where I tried to put the first a event into the html file but the new appended list of items still do not listen.
Cannot think of other work around at the moment, please help to see what would be the cause of it. Thank you.
Maybe simple try this.
$(document).on('click', 'body[data-link="media"] #media_content a')
If your element is dynamic create you should bind the click event on document and target what's element should dispatch the event.This is different to bind click only on element because the event will unbind while you remove the element.
Updated:
I'm not sure I've understand all the script you have but I try to simplify the issue.
This is the jsbin and its work correctly.
JSBin
I want all the elements with id #text-field to be hidden (if the browser support JS, that's why it should be hidden with JS). But don't get it to work with elements created this way:
// Add post
$(document).on('click', 'a.add-post', function(event)
{
// Create content based on a hidden item
var newcontent = $('.type-post#post_id-hid-0').html();
content = '<li class="type-post">' + newcontent + '</li>';
// Place new content
$('.posts-list > li.iteration-0').last().after(content);
// Load necessary JS
load_page();
event.preventDefault();
});
And my load_page() function:
$(function()
{
function load_page()
{
$('#text-field').hide();
}
load_page();
}
Use a class for text-field instead of an ID, ID's are unique for each element while a class can be used over again for this purpose.
A lightweight solution which doesn't require any JS to execute, and won't cause a 'jumpy' interface when it first loads and elements disappear in front of users eyes.
CSS:
#text-field{display:hidden;}
HTML:
<noscript>#text-field{display:block;}</noscript>
you have to do two things:
function load_page(){ //<----put this in global scope
$('.text-field').hide(); //<---hide it with class name
}
$(function(){
load_page();
});
so now somewhere in your page you might have this <input type='text' id='text-field' /> here you can change your elem's id to class this way:
<input type='text' class='text-field' />
this should help if you can replace classname with whichever dynamic page related class you insert :
$(".classname[id='text-field']").hide();
or
$(".classname[id='text-field']").attr("style", "display:none");
So I have EDIT and REMOVE buttons that are dynamically added for each data node (a "poll") in a Firebase database. I have a function which assigns onclick listeners to these with jQuery, but oddly, the event only fires when there just happens to be a single node, and hence a single pair of EDIT/REMOVE buttons. When there are multiple nodes and multiple pairs of buttons, none will fire. Here's the javascript where the events are added to the buttons...
function displayCurrentPollsForEditing(pollsRef)
{
var tbl = createTable();
var th = ('<th>Polls</th>');
$(th).attr('colspan', '3');
$(th).appendTo($(tbl).children('thead'));
pollsRef.once('value', function(pollsSnapshot) {
pollsSnapshot.forEach(function(pollsChild) {
var type = pollsChild.name();
// If this is true if means we have a poll node
if ($.trim(type) !== "NumPolls")
{
// Create variables
var pollRef = pollsRef.child(type);
var pollName = pollsChild.val().Name;
var btnEditPoll = $('<button>EDIT</button>');
var btnRemovePoll = $('<button>REMOVE</button>');
var tr = $('<tr></tr>');
var voterColumn = $('<td></td>');
var editColumn = $('<td></td>');
var rmvColumn = $('<td></td>');
// Append text and set attributes and listeners
$(voterColumn).text(pollName);
$(voterColumn).attr('width', '300px');
$(btnEditPoll).attr({
'class': 'formee-table-button',
'font-size': '1.0em'
});
$(btnRemovePoll).attr({
'class': 'formee-table-remove-button',
'font-size': '1.0em'
});
$(btnEditPoll).appendTo($(editColumn));
$(btnRemovePoll).appendTo($(rmvColumn));
// Append to row and row to table body
$(tr).append(voterColumn).append(editColumn).append(rmvColumn);
$(tr).appendTo($(tbl).children('tbody'));
// Append table to div to be displayed
$('div#divEditPoll fieldset#selectPoll div#appendPolls').empty();
$(tbl).appendTo('div#divEditPoll fieldset#selectPoll div#appendPolls');
$(btnEditPoll).click(function() {
displayPollEditOptions(pollRef);
return false;
});
$(btnRemovePoll).click(function() {
deletePoll($(this), pollsRef);
return false;
});
}
});
});
}
The markup would be something like the following...
<div id="divEditPoll">
<form class="formee" action="">
<fieldset id="selectPoll">
<legend>SELECT A POLL</legend>
<div class="formee-msg-success">
</div>
<div class="grid-12-12" id="appendPolls">
</div>
</fieldset>
</div>
EDIT - So I've switched some lines around and now I don't set the click() events until the buttons are appended to the document, so the button elements are definitely in the DOM when the click events are attached. So could this issue result from not setting id's for these buttons? That seems strange to me, since I'm using variable references rather than ids to attach the events.
There are two things I would check for.
First, make sure you don't have two elements with the same id. If you do, jquery may only bind to the first, or not bind at all.
Second, make sure the element is added to the dom before jquery attempts to bind the click event. If the code is running asynchronously, which can easily happen if you're using ajax, then you may be trying to bind the event before creating the element. Jquery would fail to find the element then give up silently.
you should use .on() for dynamically added button
Background
Creating a WYSIWYG editor that uses Dave Hauenstein's edit-in-place and jQuery's autocomplete plug-in.
Source Code
The code has the following parts: HTML, edit-in-place, and autocomplete.
HTML
The HTML element that becomes an edit-in-place text field:
<span class="edit" id="edit">Edit item</span>
Edit In Place
The JavaScript code that uses the edit-in-place plugin:
$('#edit').editInPlace({
url : window.location.pathname,
hover_class : 'inplace_hover',
params : 'command=update-edit',
element_id : 'edit-ac',
on_edit : function() {
return '';
}
});
The on_edit is custom code to call a function when the user clicks on the associated span element. The value returned is used to seed the text input field. In theory, the plugin should replace the span element in the DOM with an input element similar to:
<input type="text" id="edit-ac" />
Autocomplete
The autcomplete code:
$('#edit-ac').autocomplete({
source : URL_BASE + 'search.php',
minLength : 2,
delay : 25
});
Problem
It seems that the timing for the autocomplete code is incorrect with respect to the timing for the edit-in-place code.
I think that the edit-in-place plugin needs to call the autocomplete code snippet after the input field has been added to the DOM.
Question
How would you integrate the two plugins so that when a user clicks on the edit-in-place field that the autocomplete code provides autocomplete functionality on the DOM element added by edit-in-place?
Thank you!
Solution
Modify the jQuery in-place-editor source code by instructing the code to append an identifier onto the input field.
jQuery in-place-editor Updates
This section details the updates required.
Type Definition
Provide new attributes in the default settings:
editor_id: "inplace_id", // default ID for the editor input field
on_create: null, // function: called after the editor is created
inputNameAndClass
Change the inputNameAndClass function to use the editor_id setting:
/**
* Returns the input name, class, and ID for the editor.
*/
inputNameAndClass: function() {
var result = ' name="inplace_value" class="inplace_field" ';
// DJ: Append the ID to the editor input element.
if( this.settings.editor_id ) {
result += 'id="' + this.settings.editor_id + '" ';
}
return result;
},
replaceContentWithEditor
Change the replaceContentWithEditor function to call the create function:
replaceContentWithEditor: function() {
var buttons_html = (this.settings.show_buttons) ? this.settings.save_button + ' ' + this.settings.cancel_button : '';
var editorElement = this.createEditorElement(); // needs to happen before anything is replaced
/* insert the new in place form after the element they click, then empty out the original element */
this.dom.html('<form class="inplace_form" style="display: inline; margin: 0; padding: 0;"></form>')
.find('form')
.append(editorElement)
.append(buttons_html);
// DJ: The input editor is part of the DOM and can now be manipulated.
if( this.settings.on_create ) {
this.settings.on_create( editorElement );
}
},
Autocomplete Coupling
The autocomplete functionality can now be activated the edit-in-place is revealed.
Combined Call
The HTML snippet remains the same as before. The new call to editInPlace resembles:
$('#edit').editInPlace({
url : window.location.pathname,
hover_class : 'inplace_hover',
params : 'command=update-edit',
editor_id : 'edit-ac',
on_create : function( editor ) {
$('#edit-ac').autocomplete({
source : URL_BASE + 'search.php',
minLength : 2,
delay : 25
});
},
on_edit : function() {
return '';
}
});
This attaches the autocomplete function to the in-place-editor whenever the in-place-editor is activated.