I've made a script based on : update properties of geojson to use it with leaflet
>>>Working script picture
But I have an issue with multiple arguments.. I'd like to put 2 separate variables like:
layer.feature.properties.desc = content.value;
layer.feature.properties.number = content2.value;
But
layer.bindPopup(content).openPopup()
can open only one - "content", there is an error when I put for example:
layer.bindPopup(content + content2).openPopup();
>>> Picture
So I made another script:
function addPopup(layer)
{let popupContent =
'<form>' +
'Description:<br><input type="text" id="input_desc"><br>' +
'Name:<br><input type="text" id="input_cena"><br>' +
'</form>';
layer.bindPopup(popupContent).openPopup();
document.addEventListener("keyup", function() {
link = document.getElementById("input_desc").value;
cena = document.getElementById("input_cena").value;
layer.feature.properties.link = link;
layer.feature.properties.cena = cena;
});
};
>>>Picture
But unfortunately:
layer.feature.properties.link = link;
layer.feature.properties.cena = cena;
Is the same for each drawn geometry. Moreover when user fill the form, the arguments will dissaper just after close PopUp.. With update properties of geojson to use it with leaflet script inscribed argument is visible each time when user "click" on PupUp
Can any one help me on this?
You have to add the listener in the popupopen event.
Change your addPopup function to:
var openLayer;
function addPopup(layer){
let popupContent =
'<form>' +
'Description:<br><input type="text" id="input_desc"><br>' +
'Name:<br><input type="text" id="input_cena"><br>' +
'</form>';
layer.bindPopup(popupContent).openPopup();
layer.on("popupopen", function (e) {
var _layer = e.popup._source;
if(!_layer.feature){
_layer.feature = {
properties: {}
};
}
document.getElementById("input_desc").value = _layer.feature.properties.link || "";
document.getElementById("input_cena").value = _layer.feature.properties.cena || "";
document.getElementById("input_desc").focus();
openLayer = _layer;
});
layer.on("popupclose", function (e) {
openLayer = undefined;
})
};
L.DomEvent.on(document,"keyup",function(){
if(openLayer){
link = document.getElementById("input_desc").value;
cena = document.getElementById("input_cena").value;
openLayer.feature.properties.link = link;
openLayer.feature.properties.cena = cena;
}
})
https://jsfiddle.net/falkedesign/ntvzx7cs/
Related
I currently have a page that has content that expands when you click on a term, but as soon as you click on a new term the old one closes and the new one expands. The terms are loaded in from a google sheet onto the page. This is on a HTML page but the javascript code to do the work is the following:
// Address of the Google Sheets Database
var public_spreadsheet_url = 'sheet link here';
// Column Names from Google Sheets Database
let questionsColumn = "Question";
let answersColumn = "Answer";
window.addEventListener('DOMContentLoaded', init) // Calls method init when Sheets has loaded
function init() {
Tabletop.init( { key: public_spreadsheet_url,
callback: showInfo,
simpleSheet: true } );
}
var unhiddenAnswer = "";
// Method that gets called when data has been pulled from Google Sheets
function showInfo(data) {
var editButton = '<center><a style="border-bottom: none" href="' + public_spreadsheet_url + '"><button class="button admin">Edit</button></a></center>';
// Injects the built HTML code into the div Dynamic
document.getElementById("dynamic").innerHTML = buildFAQTable(data) + editButton;
}
// Builds the HTML Table code from the Database Data
function buildFAQTable(data) {
var index = 0;
var content = '<h2>Title Here</h2><div style="padding:0px 5%">';
data.forEach(form => {
content += '<h1 class="faq_question" onClick="unhideAnswer(' + index + ')">' + data[index][questionsColumn] + '</h1>';
content += '<p id="answer' + index + '" class="hideAnswer">' + data[index][answersColumn] + '</p>';
index++;
});
// Extends body to accomdate for tall footer on very small devices (e.g. iPhone 5/5S/SE)
content += "<br></br><br></br>";
return content;
}
// When a FAQ Question gets clicked on, this method will hide the currently displaying answer (if any), and
// Unhide the answer corresponding to the clicked on answer.
// If the currently displaying answer is the same as the answer corresponding to the clicked on question,
// it will be hidden and no new answer will be unhidden
function unhideAnswer(number) {
var answerID = "answer" + number;
if (answerID != unhiddenAnswer) {
document.getElementById(answerID).classList.remove("hideAnswer");
}
if (unhiddenAnswer != "")
document.getElementById(unhiddenAnswer).classList.add("hideAnswer");
if (unhiddenAnswer == answerID)
unhiddenAnswer = ""
else
unhiddenAnswer = answerID;
}
I want to now add an expand all/ collapse all button to give the user the option to open and view all the terms at one if needed. However, if not using the expand all button, the regular open and close functionality above should be used. I am new to javascript and am at a loss on the best way to implement this. Any help would be appreciated.
add a answer class to every answer, then you can loop through all of them with this query selector
// in your buildFAQTable fucntion
content += '<p id="answer' + index + '" class="hideAnswer answer">' + data[index][answersColumn] + '</p>';
document.querySelectorAll('.answer').forEach(answer => {
// you can use toggle, add or remove to change the appearance of the answer
answer.classList.toggle('hideAnswer')
})
i would also recomend you to check out some of the newer javascript features like string interpolation and avoid using var, but it is not so important if you are just starting out.
(i also refactored some of your code, this might make it a bit more readable)
// Address of the Google Sheets Database
const public_spreadsheet_url = 'sheet link here';
// Column Names from Google Sheets Database
const questionsColumn = "Question";
const answersColumn = "Answer";
function toggleAnswer(num) {
const answer = document.getElementById(`answer${num}`);
answer.classList.toggle('hideAnswer');
}
function hideAll() {
document.querySelectorAll('answer').forEach(answer => {
answer.classList.add('hideAnswer');
})
}
function showAll() {
document.querySelectorAll('answer').forEach(answer => {
answer.classList.remove('hideAnswer');
})
}
function buildFAQTable(data) {
let index = 0;
let content = '<h2>Title Here</h2><div style="padding:0px 5%">';
for (i in data) {
content += `<h1 class="faq_question" onClick="unhideAnswer(${i})">${data[i][questionsColumn]}</h1>`;
content += `<p id="answer${i}" class="hideAnswer answer">${data[i][answersColumn]}</p>`;
}
content += "<br></br><br></br>";
return content;
}
function showInfo(data) {
const editButton = `<center><a style="border-bottom: none" href="${public_spreadsheet_url}"><button class="button admin">Edit</button></a></center>`;
document.getElementById("dynamic").innerHTML = buildFAQTable(data) + editButton;
}
window.addEventListener('DOMContentLoaded', () => {
Tabletop.init({
key: public_spreadsheet_url,
callback: showInfo,
simpleSheet: true
});
}, { once: true })
I have asked something similar in the past but was able to resolve it by separating the functions by events. I need to be able to pass 2 href events in one Onchange Event because it is a dropdown, OR I need to be able to tie the second function into another Event.
This works only when an alert() is inserted. Once I take the alert() out it does not work. I've tried to supress the alert while still keeping it in the code and it works fine. I do not want the alert but I want the results.
HTML Here:
<select id="PartList" class="form-control form-control-lg ml-0" onChange="SelectMain();">
JavaScript Here
function sList() {
var pl = document.getElementById("PartList");
var value = pl.options[pl.selectedIndex].value;
var text = pl.options[pl.selectedIndex].text;
str = 'URL1 HERE='+ "'" + text + "'" ;
//alert(value);
//alert(text);
window.location.href = str;
}
function SelectValue() {
var pv = document.getElementById("PartList");
var value = pv.options[pv.selectedIndex].value;
str = 'URL2 HERE' + value ;
alert(value);
window.location.href = str;
}
function SelectMain() {
sList();
SelectValue();
}
function alert(message) {
console.info(message);
}
This is resolved, for those that come to this question. The problem wasn't with the JavaScript it was because the device I was sending the commands to couldn't handle the commands that fast. I have incorporated the resolved code with troubleshooting techniques.
function sList() {
var pl = document.getElementById("PartList");
var value = pl.options[pl.selectedIndex].value;
var text = pl.options[pl.selectedIndex].text;
str = 'URL1='+ "'" + text + "'" ;
//str1 = 'http://google.com';
//alert(value);
//alert(text);
window.location.href = str;
//window.open(str1);
}
function SelectValue() {
setTimeout(function(){
var pv = document.getElementById("PartList");
var value = pv.options[pv.selectedIndex].value;
str = 'URL2=' + value ;
//str1 = 'http://aol.com';
//alert(value);
window.location.href = str;
//window.open(str1);
},1000);
}
Hi all i have code for multiple upload image, but i want only one image per upload. so I create the input file every time I clicked the upload button with the dynamic id. however I have problems checking whether the user chooses the file to upload or press the cancel button. because if the user pressed the cancel button I want to delete the input file I have created. for full sourcenya as below:
$(document).ready(function () {
$("#btnimg").click(function () {
//check input file id number
var counter = $("input[id^='upload']").length;
//add input file every btnimg clicked
var html = "<input type='file' id='upload_" + counter + "' style='display:none;'/>";
$("#result").append(html);
//trigger to dialog open file
var upload = $('#upload_' + counter);
upload.trigger('click');
upload.on('change', function () {
console.log('change fire...');
var inputFiles = this.files;
var inputFile = inputFiles[0];
var reader = new FileReader();
reader.onload = function (evt) {
var imghtml = "<img id='img_upload_" + counter + "' src='" + evt.target.result + "' width='50px;' height='50px;'/>";
$('#previewimage').append(imghtml);
};
reader.onerror = function (event) {
alert("something: " + event.target.error.code);
};
reader.readAsDataURL(inputFile);
});
//if file not selected or user press button cancel on open dialog
//upload.remove();
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<body>
<div id="result"></div>
<button id="btnimg">upload image</button>
<div id="previewimage">
</div>
</body>
thank you in advance,
You can check the .length of <input type="file"> element .files property to determine if a file is selected by user
That all sounds like an xy-problem to me.
I have not (yet) got a response from you about the why you want to do it, so I will base my answer on two probable situations:
If you want to keep track of the selected Files, in order to be able to do anything with them later (e.g send them through AJAX), then use a single <input>.
At every change event, you will store the new File in an Array, from where you will also be able to do something with later on:
(function() {
// this Array will hold our files, should be accessible to the final function 'doSomething'
var savedFiles = [];
var counter = 0;
var upload = $('#upload');
upload.on('change', onuploadchange);
$("#btnimg").click(function routeClick() {
upload.trigger('click');
});
$('#endbtn').click(function doSomething() {
console.log(savedFiles);
});
function onuploadchange() {
var inputFiles = this.files;
var inputFile = inputFiles[0];
if (!inputFile) { return; } // no File ? return
savedFiles.push(inputFile); // save this File
// don't use a FileReader here, useless and counter-productive
var url = URL.createObjectURL(inputFile);
var imghtml = "<img id='img_upload_" + counter + "' src='" + url + "' width='50px;' height='50px;'/>";
$('#previewimage').append(imghtml);
$('#endbtn').removeAttr('disabled');
}
})();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="result">
<!-- A single input to save them all-->
<input type='file' id='upload' style='display:none;' />
</div>
<button id="btnimg">upload image</button>
<div id="previewimage">
</div>
<button id="endbtn" disabled>do something with saved files</button>
If, for an obscure reason, you absolutely need to keep all the filled <input> elements in your document, then create a new one only if the last one is itself filled.
$(document).ready(function() {
$("#btnimg").click(function() {
// grab previous ones
var inputs = $("input[id^='upload']");
// get the last one we created
var last = inputs.last();
var counter = inputs.length;
console.log(counter);
var upload;
// if there is no input at all, or if the last one is already filled with a File
if (!last.length || last[0].files.length) {
console.log('create new input');
upload = makeNewInput();
} else {
// use the last one
upload = last;
}
//trigger to dialog open file
upload.trigger('click');
function makeNewInput(counter) {
var html = "<input type='file' id='upload_" + counter + "' style='display:none;'/>";
var el = $(html);
el.on('change', onuploadchange);
$('#result').append(el);
return el;
}
function onuploadchange() {
var inputFiles = this.files;
var inputFile = inputFiles[0];
var url = URL.createObjectURL(inputFile);
var imghtml = "<img id='img_upload_" + counter + "' src='" + url + "' width='50px;' height='50px;'/>";
$('#previewimage').append(imghtml);
}
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="result"></div>
<button id="btnimg">upload image</button>
<div id="previewimage">
</div>
I have the following code, which creates a custom element, encapsulated with Shadow DOM:
'use strict'
var proto = Object.create(HTMLElement.prototype);
proto.createdCallback = function() {
var root = this.createShadowRoot();
var divEl = document.createElement('div');
divEl.setAttribute("id", "container");
divEl.innerHTML =
"<input id='input' type='text'>"
+ "<br>"
+ "Result: <span id='result'></span>"
+ "<br><button onclick='performTask()'>Run</button>";
root.appendChild(divEl);
};
document.registerElement('custom-ele', {
prototype: proto
});
The idea is, when 'Run' is clicked, the input would be taken from the input element and processed (in performTask()), then the output placed into '#result'. My two questions are:
How would I grab the value from the input field in the Shadow DOM?
How would I place the output into #result?
This
previous stack overflow post looks like it would have answered my question, but all the suggested links are no longer valid so am wondering if anyone could point me in the right direction :)
P.S. I'd rather not use templates since HTML Imports are not being supported by all browsers and I want all of my custom element code contained in one file.
Turns out you can add functions to the shadow root itself, then you can just call this.parentNode.fn() on the shadow roots direct children to access the shadowRoot...
proto.createdCallback = function() {
let root = this.createShadowRoot();
root.innerHTML = "<input id='input' type='text'>"
+ "<br>"
+ "Result: <span id='result'></span>"
+ "<br><button onclick='this.parentNode.process()'>Run</button>";
this.shadowRoot.process = function() {
let spanEle = this.querySelector('span');
let inputEle = this.querySelector('input');
spanEle.textContent = performAlgorithm(inputEle.value.split(','));
};
};
document.registerElement('custom-ele', { prototype: proto });
(Thanks to MarcG for giving me the initial insight)
WITH CLOSURE
You can use the method querySelector on your Shadow DOM root to get inside elements:
'use strict'
var proto = Object.create( HTMLElement.prototype )
proto.createdCallback = function ()
{
//HTML ROOT
var root = this.createShadowRoot()
root.innerHTML = "<input id='input' type='text'>"
+ "<br>"
+ "Result: <span id='result'></span>"
+ "<br><button>Run</button>"
//UI
var buttonEle = root.querySelector( "button" )
var inputEle = root.querySelector( "input" )
var spanEle = root.querySelector( "#result" )
buttonEle.onclick = function ()
{
var input = inputEle.value
// do some processing...
spanEle.textContent = input
}
}
document.registerElement( 'custom-ele', { prototype: proto } )
NB: you can use template without HTML Imports, in the same page. See the following snippet:
<html>
<body>
<custom-ele></custom-ele>
<template id="custelem">
<input id='input' type='text'>
<br>Result:
<span id='result'></span>
<br>
<button>Run</button>
</template>
<script>
var proto = Object.create(HTMLElement.prototype)
proto.createdCallback = function() {
//HTML ROOT
var root = this.createShadowRoot()
root.innerHTML = custelem.innerHTML
//UI
var buttonEle = root.querySelector("button")
var inputEle = root.querySelector("input")
var spanEle = root.querySelector("#result")
buttonEle.onclick = function() {
var input = inputEle.value
// do some processing...
spanEle.textContent = input
}
}
document.registerElement('custom-ele', {
prototype: proto
})
</script>
</body>
</html>
WITHOUT CLOSURE
If you don't want to use closure, you can declare a method called handleEvent on your custom element, and add an Event Listener that will redirect on it:
proto.createdCallback = function ()
{
//HTML ROOT
var root = this.createShadowRoot()
root.innerHTML = custelem.innerHTML
//EVENT
var buttonEle = root.querySelector( "button" )
buttonEle.addEventListener( "click", this )
}
proto.handleEvent = function ( ev )
{
var inputEle = this.shadowRoot.querySelector( "input" )
var spanEle = this.shadowRoot.querySelector( "#result" )
// do some processing...
spanEle.textContent = inputEle.value
}
I have a JQuery function that fetches and displays a page worth of images through the use of JSON files. I want to display the next set of images upon a button click, but that requires adding on a short string to the request url, which is found and stored in a var when I first run the script. I need to call this JQuery function again and pass the string var to it (lastId in code below). I am an utter noob with JavaScript in general and don't know how to go about doing that.
Here is a full version of the code:
$(function runthis(un){
var lastId;
un = typeof un !== 'undefined' ? un : "";
$('#domainform').on('submit', function(event){
event.preventDefault();
$('#content').html('<center><img src="img/loader.gif" alt="loading..."></center>');
//var lastId;
var domain = $('#s').val();
var newdomain = domain.replace(/\//g, ''); // remove all slashes
var requrl = "http://www.reddit.com/r/";
var getmore;
getmore = "?after=t3_"+un;
var fullurlll = requrl + domain + ".json" + getmore;
$.getJSON(fullurlll, function(json){
var listing = json.data.children;
var html = '<ul class="linklist">\n';
for(var i=0, l=listing.length; i<20; i++) {
var obj = listing[i].data;
var votes = obj.score;
var title = obj.title;
var subtime = obj.created_utc;
var thumb = obj.thumbnail;
var subrdt = "/r/"+obj.subreddit;
var redditurl = "http://www.reddit.com"+obj.permalink;
var subrdturl = "http://www.reddit.com/r/"+obj.subreddit+"/";
var exturl = obj.url;
var imgr = exturl;
var imgrlnk = imgr.replace("target=%22_blank%22","");
var length = 14;
var myString = imgrlnk;
var mycon = imgrlnk;
var end = mycon.substring(0,14);
myString.slice(-4);
var test1 = myString.charAt(0);
var test2 = myString.charAt(1);
var timeago = timeSince(subtime);
if(obj.thumbnail === 'default' || obj.thumbnail === 'nsfw' || obj.thumbnail === '')
thumb = 'img/default-thumb.png';
if(end == "http://i.imgur" ){
$("#MyEdit").html(exturl);
html += '<li class="clearfix">\n';
html += '<img src="'+imgrlnk+'" style="max-width:100%; max-height:750px;">\n';
html += '</li>\n';
html += '<div class="linkdetails"><h2>'+title+'</h2>\n';
/*html += '<p class="subrdt">posted to '+subrdt+' '+timeago+'</p>'; /*'+test1+test2+'*/
html += '</div></li>\n';
}
if (listing && listing.length > 0) {
lastId = listing[listing.length - 1].data.id;
} else {
lastId = undefined;
}
} // end for{} loop
htmlOutput(html);
}); // end getJSON()
}); // end .on(submit) listener
function htmlOutput(html) {
html += '</ul>';
$('#content').html(html);
}
});
The way you currently are executing the function run this doesn't ever leave you a handle to that function. This means it only really exists in the context of document.ready (what $(function()) is a shortcut for).
What you want to do instead is to keep a reference to this function for later use.
If you want to be able to put it directly into an onclick='' you will need to put the function in global,
eg:
var myFunction = function() { /*Stuff here*/}
$(myFunction)
this declares a function called myFunction and then tells jQuery to execute it on document ready
Global is generally considered pretty naughty to edit. One slightly better option would be to assign the click to the button inside your javascript
eg:
$(function(){
var myFunction = function() { /*Stuff here*/}
myFunction(); //call it here
$('#my-button-id').click(myFunction);//attach a click event to the button
)
This means that the function myFunction only exists in the scope of your document.ready, not in global scope (and you don't need onclick='' at all)
tTo add listener on some event you can use live('click',function(){}) Like yhis:
<div id="my-button">some content</div>
<script type="text/javascript">
$('#my-button').live('click',function(){
//your code
})
</script>