How to use the numericRefinementList to set allowed distances? - algolia

I would like to be able to use the numericRefinementList to allow users to pick the distance from themselves an item can be? This would be using the IP geo-location feature or inputting the geo-location from browser if available.
Less than 50km
50 - 100km
100 - 150km
More than 150km
https://community.algolia.com/instantsearch.js/documentation/#numericrefinementlist

This is unfortunately not something you can do with the numericRefinementList but you can probably build a custom widget setting the aroundRadius depending on the link you've clicked on:
function radiusList(options) {
if (!options.container) {
throw new Error('radiusList: usage: radiusList({container, ...})');
}
var $container = $(options.container);
if ($container.length === 0) {
throw new Error('radiusList: cannot select \'' + options.container + '\'');
}
return {
init: function(args) {
// event delegation: set the aroundRadius of the underlying link
$(document).on('click', '.radius-link', function(e) {
e.preventDefault();
args.helper.setQueryParameter('aroundRadius', +$(this).data('radius'));
args.helper.search();
});
},
render: function(args) {
// FIXME: display the list of radius links
var html = '<ul>';
html += '<li>< 100km</li>';
html += '</ul>';
$container.html(html);
}
};
}
And then you use it with:
search.addWidget(radiusList({container: '#my-radius-list'}));

Related

hide ul when user clicks anywhere site

my code is :
function autocomplet() {
var min_length = 0; // min caracters to display the autocomplete
var keyword = $('#country_id').val();
if (keyword.length >= min_length) {
$.ajax({
url: 'ajaxname.php',
type: 'POST',
data: {keyword:keyword},
success:function(data){
$('#country_list_id').show();
$('#country_list_id').html(data);
}
});
} else {
$('#country_list_id').hide();
}
}
function set_item(item) {
// change input value
$('#country_id').val(item);
// hide proposition list
$('#country_list_id').hide();
}
and i wana hide ul (country_list_id) when user click on anywhere ?
and im not good in ajax :(
so any one can edit this code
Assuming you just want to hide the id when the user click basically anything.
Then here.
$(document).on("click", () => {
$('#country_list_id').hide();
})

Leaflet Trigger Event on Clustered Marker by external element

I just starting to learn about Leaflet.js for my upcoming project.
What i am trying to accomplish:
I need to make a list of marker which displayed on the map, and when the list item is being hovered (or mouseover) it will show where the position on the map (for single marker, it should change its color. For Clustered marker, it should display Coverage Line like how it behave when we hover it.. and perhaps change its color too if possible).
The map should not be changed as well as the zoom level, to put it simply, i need to highlight the marker/ Cluster on the map.
What i have accomplished now : I am able to do it on Single Marker.
what i super frustrated about : I failed to find a way to make it happen on Clustered Marker.
I use global var object to store any created marker.
function updateMapMarkerResult(data) {
markers.clearLayers();
for (var i = 0; i < data.length; i++) {
var a = data[i];
var myIcon = L.divIcon({
className: 'prop-div-icon',
html: a.Description
});
var marker = L.marker(new L.LatLng(a.Latitude, a.Longitude), {
icon: myIcon
}, {
title: a.Name
});
marker.bindPopup('<div><div class="row"><h5>Name : ' + a.Name + '</h5></div><div class="row">Lat : ' + a.Latitude + '</div><div class="row">Lng : ' + a.Longitude + '</div>' + '</div>');
marker.on('mouseover', function(e) {
if (this._icon != null) {
this._icon.classList.remove("prop-div-icon");
this._icon.classList.add("prop-div-icon-shadow");
}
});
marker.on('mouseout', function(e) {
if (this._icon != null) {
this._icon.classList.remove("prop-div-icon-shadow");
this._icon.classList.add("prop-div-icon");
}
});
markersRef[a.LocId] = marker; // <-- Store Reference
markers.addLayer(marker);
updateMapListResult(a, i + 1);
}
map.addLayer(markers);
}
But i don't know which object or property to get the Clustered Marker reference.
And i trigger the marker event by my global variable (which only works on single marker).
...
li.addEventListener("mouseover", function(e) {
jQuery(this).addClass("btn-info");
markersRef[this.getAttribute('marker')].fire('mouseover'); // --> Trigger Marker Event "mouseover"
// TODO : Trigger ClusteredMarker Event "mouseover"
});
...
This is my current https://jsfiddle.net/oryza_anggara/2gze75L6/, any lead could be a very big help. Thank you.
Note: the only js lib i'm familiar is JQuery, i have no knowledge for others such as Angular.js
You are probably looking for markers.getVisibleParent(marker) method, to retrieve the containing cluster in case your marker is clustered.
Unfortunately, it is then not enough to fire your event on that cluster. The coverage display functionality is set on the Cluster Group, not on its individual clusters. Therefore you need to fire your event on that group:
function _fireEventOnMarkerOrVisibleParentCluster(marker, eventName) {
var visibleLayer = markers.getVisibleParent(marker);
if (visibleLayer instanceof L.MarkerCluster) {
// In case the marker is hidden in a cluster, have the clusterGroup
// show the regular coverage polygon.
markers.fire(eventName, {
layer: visibleLayer
});
} else {
marker.fire(eventName);
}
}
var marker = markersRef[this.getAttribute('marker')];
_fireEventOnMarkerOrVisibleParentCluster(marker, 'mouseover');
Updated JSFiddle: https://jsfiddle.net/2gze75L6/5/
That being said, I think another interesting UI, instead of showing the regular coverage polygon that you get when "manually" hovering a cluster, would be to spiderfy the cluster and highlight your marker. Not very easy to implement, but the result seems nice to me. Here is a quick try, it would probably need more work to make it bullet proof:
Demo: https://jsfiddle.net/2gze75L6/6/
function _fireEventOnMarkerOrVisibleParentCluster(marker, eventName) {
if (eventName === 'mouseover') {
var visibleLayer = markers.getVisibleParent(marker);
if (visibleLayer instanceof L.MarkerCluster) {
// We want to show a marker that is currently hidden in a cluster.
// Make sure it will get highlighted once revealed.
markers.once('spiderfied', function() {
marker.fire(eventName);
});
// Now spiderfy its containing cluster to reveal it.
// This will automatically unspiderfy other clusters.
visibleLayer.spiderfy();
} else {
// The marker is already visible, unspiderfy other clusters if
// they do not contain the marker.
_unspiderfyPreviousClusterIfNotParentOf(marker);
marker.fire(eventName);
}
} else {
// For mouseout, marker should be unclustered already, unless
// the next mouseover happened before?
marker.fire(eventName);
}
}
function _unspiderfyPreviousClusterIfNotParentOf(marker) {
// Check if there is a currently spiderfied cluster.
// If so and it does not contain the marker, unspiderfy it.
var spiderfiedCluster = markers._spiderfied;
if (
spiderfiedCluster
&& !_clusterContainsMarker(spiderfiedCluster, marker)
) {
spiderfiedCluster.unspiderfy();
}
}
function _clusterContainsMarker(cluster, marker) {
var currentLayer = marker;
while (currentLayer && currentLayer !== cluster) {
currentLayer = currentLayer.__parent;
}
// Say if we found a cluster or nothing.
return !!currentLayer;
}

How to remove certain elements before taking screenshot?

I am able to take screenshot of the page using the example code below:
html2canvas(document.body, {
onrendered: function(canvas) {
document.body.appendChild(canvas);
}
});
Now there are certain div's i dont want to be part of the page when I take the screenshot?
How can i prevent them from being part of the screenshot.
One way I thought was to clone the element and then remove the elements, but taking a screenshot of the clone gives a white screen. Here is the code I used:
html2canvas($(document.body).clone()[0], {
onrendered: function(canvas) {
document.body.appendChild(canvas);
}
});
Add this attribute: data-html2canvas-ignore to any element you don't want to be taken when the screenshot is processed.
Hopefully this will help the next guy.
When I used this library I faced a problem that the lib download all the images in my application, that cause the application to run slowly. I resolved the problem using the ignoreElements option.
This is my code:
var DropAreaElement= document.getElementById("123");
var config= {
useCORS: true,
ignoreElements: function (element) {
if (element.contains(DropAreaElement) || element.parentElement.nodeName =="HTML" || element == DropAreaElement || element.parentNode == DropAreaElement) {
console.log("elements that should be taken: ", element)
return false;
}else {
return true;
}
}
};
html2canvas(DropAreaElement, config).then(function (canvas){
var imgBase64 = canvas.toDataURL('image/jpeg', 0.1);
console.log("imgBase64:", imgBase64);
var imgURL = "data:image/" + imgBase64;
var triggerDownload = $("<a>").attr("href", imgURL).attr("download", "layout_" + new Date().getTime() + ".jpeg").appendTo("body");
triggerDownload[0].click();
triggerDownload.remove();
}).catch(Delegate.create(this, function (e){
console.error("getLayoutImageBase64 Exception:", e);
});
If you don't want to use an attribute, html2canvas does provide a method to remove elements. For example:
html2canvas( document.body, {
ignoreElements: function( element ) {
/* Remove element with id="MyElementIdHere" */
if( 'MyElementIdHere' == element.id ) {
return true;
}
/* Remove all elements with class="MyClassNameHere" */
if( element.classList.contains( 'MyClassNameHere' ) ) {
return true;
}
}
} ).then( function( canvas ) {
document.body.appendChild( canvas );
} );
For more information, see html2canvas options.
You can create HOC for <Printable/> and <NonPrintable/> , you can wrap your component with <NonPrintable><YourCoolComponent/></NonPrintable>
those children components would be excluded.
import React from "react"
interface INonPrintable {
children: React.ReactChildren
}
/*
HOC - Printable which injects the printId to the React component
which gets us Printable Context to html2canvas => jsPDF
eg:
<Printable printId="about-you-print">
<PersonalInfo badEmail={badEmail} />
<IdentityInfo />
<AdditonalInfo />
<AddressInfo
serviceAddress={serviceAddress}
billingAddress={this.state.billingAddress}
setBillingAddress={this.setBillingAddress}
/>
</Printable>
*/
export default function Printable({ printId = "", children, ...restProps }) {
return <div print-id={printId} {...restProps}>{children}</div>
}
/*
HOC - NONPrintable which injects the data-html2canvas-ignore to the React component
which gets us Printable Context to html2canvas => jsPDF
eg:
<NonPrintable style={{display:"flex",justifyContent:'space-around'}}>
<Button
text="Print PDF using Own utility"
onClick={this.handlePrintPdf}
/>
<Button
text="Print PDF using html2canvas + jsPDF"
onClick={this.handlePrintwithPDFjs}
/>
</NonPrintable>
*/
export const NonPrintable = ({ children, ...restProps }) => {
return <div data-html2canvas-ignore {...restProps}>{children}</div>
}

kendo-ui autocomplete extend

I'm trying to extend the kendo-ui autocomplete control: I want the search start when te user hit enter, so basically I've to check the user input on keydown event.
I've tried to catch the keydown event with this code:
(function($) {
ui = kendo.ui,
Widget = ui.Widget
var ClienteText = ui.AutoComplete.extend({
init: function(element,options) {
var that=this;
ui.AutoComplete.fn.init.call(this, element, options);
$(this).bind('keydown',function(e){ console.log(1,e); });
$(element).bind('keydown',function(e){ console.log(2,e); });
},
options: {
[...list of my options...]
},
_keydown: function(e) {
console.log(3,e);
kendo.ui.AutoComplete.fn._keydown(e);
}
});
ui.plugin(ClienteText);
})(jQuery);
None of the binded events gets called, only the _keydown, and then I'm doing something wrong and cannot call the autocomplete "normal" keydown event.
I've seen a lot of examples that extend the base widget and then create a composite widget, but I'm not interested in doing that, I only want to add a functionality to an existing widget.
Can someone show me what I'm doing wrong?
Thank you!
What about avoiding the extend and take advantage of build in options and methods on the existing control : http://jsfiddle.net/vojtiik/Vttyq/1/
//create AutoComplete UI component
var complete = $("#countries").kendoAutoComplete({
dataSource: data,
filter: "startswith",
placeholder: "Select country...",
separator: ", ",
minLength: 50 // this is to be longer than your longest char
}).data("kendoAutoComplete");
$("#countries").keypress(function (e) {
if (e.which == 13) {
complete.options.minLength = 1; // allow search
complete.search($("#countries").val());
complete.options.minLength = 50; // stop the search again
}
});
This code actually work:
(function($) {
ui = kendo.ui,
ClienteText = ui.AutoComplete.extend({
init: function(element,options) {
ui.AutoComplete.fn.init.call(this, element, options);
$(element).bind('keydown',function(e){
var kcontrol=$(this).data('kendoClienteText');
if (e.which === 13) {
kcontrol.setDataSource(datasource_clientes);
kcontrol.search($(this).val());
} else {
kcontrol.setDataSource(null);
}
});
},
options: {
name: 'ClienteText',
}
});
ui.plugin(ClienteText);
})(jQuery);
but I don't know if it's the correct way to do it.

AngularJS: Move to next form input element after successful validation

I have written a custom directive for validation of my form fields. When certain criteria are met (i.e. it is dirty and valid), I want to set the focus automatically to the next input element. This is a requirement from my users, such that they can move through the forms most efficiently.
The simplified directive looks like this:
directive('custom', ['$parse', function($parse) {
return {
restrict: 'A',
require: ['ngModel', '^ngController'],
link: function(scope, element, attrs, ctrls) {
var model=ctrls[0], form=ctrls[1];
scope.next = function(){
return model.$valid
}
scope.$watch(scope.next, function(newValue, oldValue){
if (newValue && model.$dirty){
???
}
})
Now my question is: how can I identify
- the next input element (which is the next sibling) or possibly via the tabindex
- and focus on it
without using Jquery?
For me, it is currently not clear, how to get to the next input element from the available "scope" or "element" attributes without Jquery; and JQlite does nothave a "focus" method. Basically, I need a working substitute for ??? in my code.
Any help is highly appreciated. Thanks
Juergen
You can use [0] to get the underlying input element (which has a focus() function) from the angular/jqLite object (which doesn't).
app.directive('custom', ['$parse', function($parse) {
return {
restrict: 'A',
require: ['ngModel'],
link: function(scope, element, attrs, ctrls) {
var model=ctrls[0], form=ctrls[1];
scope.next = function(){
return model.$valid;
}
scope.$watch(scope.next, function(newValue, oldValue){
if (newValue && model.$dirty)
{
var nextinput = element.next('input');
if (nextinput.length === 1)
{
nextinput[0].focus();
}
}
})
}
}
}])
http://jsfiddle.net/Y2XLA/
element.next().focus() might not work if you have a complex form and input are nested into different divs.
I ended writing this directive (here I move the focus on Enter, but can be adapted to whatever event):
.directive('enterToTab', function($timeout) {
return {
restrict: 'A',
link: function(scope, element, attrs) {
var procAttr = 'data-ett-processed';
$timeout(function() { // Use $timeout to run the directive when the DOM is fully rendered
var formElements = element[0].querySelectorAll('input:not([' + procAttr + '="true"]), select:not([' + procAttr + '="true"]), textarea:not([' + procAttr + '="true"])');
// Run through all elements in form
var formElementsLength = formElements.length;
for (var i = 0; i < formElementsLength; i++) { // Add tabindex attribute
formElements[i].setAttribute('tabindex', i + 1);
// Go to next element on Enter key press
formElements[i].addEventListener('keypress', function(event) {
if (event.keyCode === 13) { // Enter
// Prevent Angular from validating all the fields and submitting
if (event.target.tagName !== 'TEXTAREA') { // Not on textarea, otherwise not possible to add new line
event.stopPropagation();
event.preventDefault();
}
var nextIndex = parseInt(event.target.getAttribute('tabindex')) + 1;
// Move focus to next element
// TODO: find next visible element
var nextElem = element[0].querySelector('[tabIndex="' + (nextIndex) + '"]');
if (nextElem) {
nextElem.focus();
}
}
});
formElements[i].setAttribute(procAttr, true); // Add attribute to prevent adding 2 listeners on same element
}
});
}
};
});
Event should be in HTML component (keypress) = "keyFocus($event)"
Method shoulb be like .ts file.
keyFocus(input1){
input1.srcElement.nextElementSibling.focus();
}
AngularJS already contains a light version of jQuery so you can as well use it...
http://docs.angularjs.org/api/angular.element
You could try something like this:
element.next().focus()