detect dynamically checkboxes/polymer elements ticked in Dart - dom

A newbie to Dart with no experience in JS.
I have written code to populate a dropdown from JSON.
Edit:
i am trying to add polymer elements.
Polymer .dart
import 'package:polymer/polymer.dart';
#CustomTag('player-item')
class PlayerItem extends PolymerElement{
#observable String playerName='hello';
void removePlayer(){
playerName='';
}
PlayerItem.created(): super.created(){}
}
Initially was getting error of constructor not defined. added empty brackets to
super.created. error fixed
What am i doing wrong. how to do this correctly??
polymer.html
playername = name of player to be displayed dynamically.
right now using default string.
removeplayer = (ideas is to) remove entire polymer element.
<polymer-element name="player-item">
<template>
<input type="image" src="button_minus_red.gif" on-click="{{removePlayer}}">
<div>{{playerName}}</div>
</template>
<script type="application/dart" src="player-item.dart"></script>
</polymer-element>
Edited Dart Code:
Objective is first generate options then select one of them and the subsequently remove them if clicked on image(polymer element intended for this purpose).
Went through polymer example master. but couldnt find something related.
Help Needed:
1. how do i dynamically add polymer elements?
how to pass values (ie. in this case name of player) to the dynamically added
polymer element?
how to remove polymer elements?
How to remove appended text added via *.appendedtext ?
import 'dart:html';
import 'dart:convert' show JSON;
import 'dart:async' show Future;
import 'package:polymer/polymer.dart';
import 'player-item.dart';
//ButtonElement genButton,desButton;
SelectElement selectTeam;
FormElement teamPlayer;
FormElement yourPlayer;
InputElement teamPlayers;
//final subscriptions = <StreamSubscription>[];
List<String>teams=[];
List<String>players=[];
main() async{
selectTeam = querySelector('#teamNames');
teamPlayer = querySelector('#teamPlayers');
yourPlayer = querySelector('#yourPlayers');
selectTeam.onChange.listen(populateTeams);
try {
await prepareTeams1 ();
selectTeam.disabled = false; //enable
//genButton.disabled = false;
} catch(arrr) {
print('Error initializing team names: $arrr');
}
}
void populateYourPlayers(String name){
querySelector('#yourPlayers').children.add(new Element.tag('player-item'));
var input = new InputElement();
input.type = "image";
input.src = "button_minus_red.gif";
input.id = name;
print('yo');
input.width = 15;
input.height =15;
input.appendText(name);
input.onClick.listen((remove){
remove.preventDefault();
input.remove();
//yourPlayer.children.remove();
});
yourPlayer.append(input);
// yourPlayer.append(y);
yourPlayer.appendText(name);
yourPlayer.appendHtml("<br>");
}
void removeYourPlayers(Event e){
yourPlayer.querySelectorAll("input[type=checkbox]").forEach((cb) {
// print('${cb.checked}');
if(cb.checked == true){
print('${cb.id}');
yourPlayer.children.removeWhere((cb)=>cb.checked==true);
}
}
);
}
Future prepareTeams1()async{
String path = 'teams.json';
String jsonString = await HttpRequest.getString(path);
parseTeamNamesFromJSON(jsonString);
}
parseTeamNamesFromJSON(String jsonString){
Map team = JSON.decode(jsonString);
teams = team['Teams'];
print(teams);
for (int i =0; i< teams.length; i++){
var option = new OptionElement();
option.value = teams[i];
option.label =teams[i];
option.selected = false;
selectTeam.append(option);
}
}
Future prepareTeams2(String Team)async{
String path = 'teams.json';
String jsonString = await HttpRequest.getString(path);
parsePlayerNamesFromJSON(jsonString, Team);
}
parsePlayerNamesFromJSON(String jsonString,String Team){
Map team = JSON.decode(jsonString);
teamPlayer.children.clear();
teams = team[Team];
print(teams);
for (int i =0; i< teams.length; i++){
var input = new InputElement(type:"image");
// input.type = "image";
input.id = teams[i];
input.src = "button_plus_green.gif";
input.width = 15;
input.height =15;
input.onClick.listen((p){
p.preventDefault();
populateYourPlayers(teams[i]);
});
//input.onClick.listen((event){populateYourPlayers(teams[i]);});
//subscription.cancel();
teamPlayer.append(input);
teamPlayer.appendText(teams[i]);
teamPlayer.appendHtml("<br>");
}
}
void populateTeams(Event e){
print('selectTeam.length: ${selectTeam.length}');
print(selectTeam.value);
prepareTeams2(selectTeam.value);
if (selectTeam.length == 0){
}
}
Modified HTML:
<html>
<head>
<meta charset="utf-8">
<title>Pirate badge</title>
<meta name="viewport"
content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="piratebadge.css">
<link rel="import" href="player-item.html">
</head>
<body>
<h1>Team Names</h1>
<select id="teamNames">
</select>
<h1>Team players</h1>
<form id="teamPlayers">
</form>
<div>
<button id="generateButton" disabled>Add Player/Players</button>
</div>
<h1>Your players</h1>
<form id="yourPlayers">
</form>
<player-item></player-item>
<div>
<button id="destroyButton" disabled>Remove Player/Players</button>
</div>
<script type="application/dart" src="piratebadge.dart"></script>
<script src="packages/browser/dart.js"></script>
</body>
</html>
and based on that selection display a form with checkboxes.
The issue i am facing is how to detect them which checkboxes have been checked and if so how the value of that checkbox can be captured.
Possible duplicate
How to know if a checkbox or radio button is checked in Dart?
However them checkboxes not dynamically created.
If the above approach is wrong, kindly advise.

Depending on when you want to detect the checked state there are two ways.
You can add a click handler to the submit button and then query the checkboxes.
querySelector("input[type=submit]").onClick.listen((e) {
querySelectorAll("input[type=checkbox]").forEach((cb) {
print('${cb.id} {cb.checked}');
});
});
Currently you are assigning the same id to each checkbox. This is a bad choice because you have no way to know which checkbox represents what item.
Another way is to assign a click handler to each checkbox to get notified immediately when the checkbox is clicked.
(I simplified your checkbox creation code a bit by using continuations and forEach instead of for)
teams.forEach((team) {
var input = new InputElement()
..type = "checkbox"
..id = "player"
..onClick.listen((e) {
print('${cb.id} {cb.checked}');
});
teamplayer
..append(input)
..appendText(team)
..appendHtml("<br>");
}
In this case you might need to reset the click notifications when the selection changes.
import 'dart:async';
// ...
final subscriptions = <StreamSubscription>[];
// ...
subscriptions
..forEach((s) => s.cancel())
..clear();
teams.forEach((team) {
var input = new InputElement()
..type = "checkbox"
..id = "player";
subscriptions.add(input.onClick.listen((e) {
print('${cb.id} {cb.checked}');
}));
teamplayer
..append(input)
..appendText(team)
..appendHtml("<br>");
}
Caution: code not tested and it's a while I used checkboxes.

You can read the checked property of the CheckboxInputElement
parsePlayerNamesFromJSON(String jsonString,String Team){
Map team = JSON.decode(jsonString);
teams = team[Team];
print(teams);
for (int i =0; i< teams.length; i++){
var input = new CheckboxInputElement();
input.type = "checkbox";
input.id = "player";
input.onChange.listen((_) {
print("teamplayer ${input.checked}");
});
teamPlayer.append(input);
teamPlayer.appendText(teams[i]);
teamPlayer.appendHtml("<br>");
}

Related

How to manage DOM element dependencies

I am trying to create a web-page where some elements (forms and buttons) become visible or are being hidden when some other elements (buttons) are clicked.
I try to find a way to manage this, that is re-usable, and easy to maintain.
My current solution is shown below, but I hope someone has a more elegant solution.
The problem with my own solution is that it will become difficult to read when the number of dependencies increase. It will then also require a lot of editing when I add another button and form.
My current solution is to use an observable to manage the state of the forms, like this:
HTML:
<button id="button-A">Show form A, hide button A and B</button>
<button id="button-B">Show form B, hide button A and B</button>
<form id="form-A">
...this form is initially hidden
...some form elements
<button id="cancel-A">Hide form A, show button A and B</button>
</form>
<form id="form-B">
...this form is initially hidden
...some form elements
<button id="cancel-B">Hide form B, show button A and B</button>
</form>
Dart:
import 'dart:html';
import 'package:observe/observe.dart';
final $ = querySelector;
final $$ = querySelectorAll;
Map<String, bool> toBeObserved = {
"showFormA" : false,
"showFormB" : false
};
// make an observable map
ObservableMap observeThis = toObservable(toBeObserved);
// start managing dependencies
main() {
// add click event to buttons
$('#button-A')
..onClick.listen((E) => observeThis["showFormA"] = true);
$('#button-B')
..onClick.listen((E) => observeThis["showFormB"] = true);
// add click events to form buttons
$('#cancel-A')
..onClick.listen((E) {
E.preventDefault();
E.stopPropagation();
observeThis["showFormA"] = false;
});
$('#cancel-B')
..onClick.listen((E) {
E.preventDefault();
E.stopPropagation();
observeThis["showFormB"] = false;
});
// listen for changes
observeThis.changes.listen((L) {
L.where((E) => E.key == 'showFormA').forEach((R) {
$('#form-A').style.display = (R.newValue) ? 'block' : 'none';
$('#button-A').style.display = (R.newValue || observeThis['showFormB']) ? 'none' : 'inline-block';
$('#button-B').style.display = (R.newValue || observeThis['showFormB']) ? 'none' : 'inline-block';
});
L.where((E) => E.key == 'showFormB').forEach((R) {
$('#form-B').style.display = (R.newValue) ? 'block' : 'none';
$('#button-A').style.display = (R.newValue || observeThis['showFormA']) ? 'none' : 'inline-block';
$('#button-B').style.display = (R.newValue || observeThis['showFormA']) ? 'none' : 'inline-block';
});
});
}
You can use basic CSS to show/hide the elements.
HTML
<div id="container" class="show-buttons">
<button id="button-A" class="btn" data-group="a">...</button>
<button id="button-B" class="btn" data-group="b">...</button>
<form id="form-A" class="form group-a">...</button>
<form id="form-B" class="form group-b">...</button>
</div>
CSS
.btn, .form {
display: none;
}
.show-buttons .btn,
.show-a .form.group-a,
.show-b .form.group-b {
display: block;
}
In Dart just get the data-group (or whatever you want to call this) attribute from the button. Toggle the CSS classes (show-buttons, show-a and show-b) on the container element to switch between the buttons and the specific forms.
This solution is very easy to extend on.
You can use something like this to handle all the elements in a generic way :
final Iterable<ButtonElement> buttons = querySelectorAll('button')
.where((ButtonElement b) => b.id.startsWith('button-'));
final Iterable<ButtonElement> cancels = querySelectorAll('button')
.where((ButtonElement b) => b.id.startsWith('cancel-'));
final Iterable<FormElement> forms = querySelectorAll('form')
.where((FormElement b) => b.id.startsWith('form-'));
buttons.forEach((b) {
b.onClick.listen((e) {
// name of clicked button
final name = b.id.substring(b.id.indexOf('-') + 1);
// hide all buttons
buttons.forEach((b) => b.hidden = true)
// show the good form
querySelector('#form-$name').hidden = false;
});
});
cancels.forEach((b) {
b.onClick.listen((e) {
// show all buttons
buttons.forEach((b) => b.hidden = false);
// hide all forms
forms.forEach((b) => b.hidden = true);
// prevent default
e.preventDefault();
});
});
// hide all form at startup
forms.forEach((f) => f.hidden = true);
You could use polymer's template functionality like
<template if="showA">...
This should work without embedding your elements within Polymer elements too.
This discussion provides some information how to use <template> without Polymer elements.
Using Polymer elements could also be useful.
It all depends on your requirements/preferences.
Angular.dart is also useful for such view manipulation.
If you want to use plain Dart/HMTL I don't have ideas how to simplify your code.

Splitter control in SAPUI5

I am trying to implement SAPUI5 splitter button/control that accepts one Label and one button like Linked in. Like linked in when you add your skills, text display along with delete button. If you want to delete the text then simple click on delete button, it will delete (this is what happens in linked in).
I am also want to implement same thing using SAP splitter control but i am facing some layout issue. I have tried a lot to fix this issue but no luck.
Here is my code
In code there three splitters in total. Main splitter called oSplitterH that saves 0.....n sub-sublitters in its addFirstPaneContent.
The problem is it always display split button in vertical alignment rather than horizontal like linked in. I also changed the layout into Horizontal but still displaying in vertical alignment.
Any suggestion?
var splitterLabel = new Label({
text : 'Splitter ',
width: '80px'
});
var oSplitterH = new sap.ui.commons.Splitter("splitterH");
oSplitterH.setSplitterOrientation(sap.ui.commons.Orientation.Horizontal);
oSplitterH.setSplitterPosition("200%%");
oSplitterH.setMinSizeFirstPane("20%");
oSplitterH.setMinSizeSecondPane("30%");
oSplitterH.setWidth("200%");
//adding Labels to both panes
var oSplitter2 = new sap.ui.commons.Splitter("splitterH12");
oSplitter2.setSplitterOrientation(sap.ui.commons.Orientation.Vertical);
oSplitter2.setSplitterPosition("10%");
oSplitter2.setMinSizeFirstPane("10%");
oSplitter2.setMinSizeSecondPane("10%");
oSplitter2.setWidth("20%");
var oLabel2 = new sap.ui.commons.Label({text: "Part1"});
oSplitter2.addFirstPaneContent(oLabel2);
var oLabel2 = new sap.ui.commons.Label({text: "Part2"});
oSplitter2.addFirstPaneContent(oLabel2);
var oSplitter3 = new sap.ui.commons.Splitter("splitterH13");
oSplitter3.setSplitterOrientation(sap.ui.commons.Orientation.Vertical);
oSplitter3.setSplitterPosition("10%");
oSplitter3.setMinSizeFirstPane("10%");
oSplitter3.setMinSizeSecondPane("10%");
oSplitter3.setWidth("20%");
var oLabe123 = new sap.ui.commons.Label({text: "Part3"});
oSplitter3.addFirstPaneContent(oLabe123);
var oLabe1234 = new sap.ui.commons.Label({text: "Part4"});
oSplitter3.addFirstPaneContent(oLabe1234);
oSplitterH.addFirstPaneContent(oSplitter2);
oSplitterH.addFirstPaneContent(oSplitter3);
createProfileMatrix.createRow(splitterLabel, oSplitterH, null, null);
The following code may help you.
index.html
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<link rel="stylesheet" href="main.css"/>
<script src="resources/sap-ui-core.js"
id="sap-ui-bootstrap"
data-sap-ui-libs="sap.ui.commons"
data-sap-ui-theme="sap_goldreflection">
</script>
<!-- add sap.ui.table,sap.ui.ux3 and/or other libraries to 'data-sap-ui-libs' if required -->
<script>
sap.ui.localResources("sapui5samples");
var view = sap.ui.view({id:"idlinkedIn-label1", viewName:"sapui5samples.linkedIn-label", type:sap.ui.core.mvc.ViewType.JS});
view.placeAt("content");
</script>
</head>
<body class="sapUiBody" role="application">
<div id="content"></div>
<div id="list"></div>
</body>
</html>
main.css
.tech-area{
border:1px solid gray;
border-radius: 5px;
width:500px;
height:300px;
left:0;
top:50;
position:relative;
overflow:scroll;
}
SAPUI5 view file (didn't used controller file)
var oLayout;
sap.ui.jsview("sapui5samples.linkedIn-label", {
getControllerName : function() {
return "sapui5samples.linkedIn-label";
},
createContent : function(oController) {
// create a simple SearchField with suggestion list (list expander
// visible)
var oSearch = new sap.ui.commons.SearchField("suggestSearch1", {
enableListSuggest : true,
startSuggestion : 1,
search : function(oEvent) {
var techName = oEvent.getParameter("query");
addTechnology(techName);
},
suggest : doSuggest
});
// Button for adding the technology if it is not listed in the available
// technologies
var oButton = new sap.ui.commons.Button({
text : "Add",
tooltip : "Add Technology",
press : function() {
var tech = sap.ui.getCore().byId("suggestSearch1").getValue();
addTechnology(tech);
}
});
// create a simple horizontal layout
var oLayout = new sap.ui.commons.layout.HorizontalLayout({
content : [ oSearch, oButton ]
});
// attach it to some element in the page
oLayout.placeAt("content");
oLayout = new sap.ui.commons.layout.HorizontalLayout("target");
oLayout.addStyleClass("tech-area");
// attach it to some element in the page
oLayout.placeAt("list");
}
});
// Help function to handle the suggest events of the search field
var doSuggest = function(oEvent) {
var sVal = oEvent.getParameter("value");
var aSuggestions = filterTechnologies(sVal); // Find the technologies
var oSearchControl = sap.ui.getCore().byId(oEvent.getParameter("id"));
oSearchControl.suggest(sVal, aSuggestions); // Set the found suggestions on
// the search control
};
var technologies = [ "Java", ".Net", "PHP", "SAPUI5", "JQuery", "HTML5", "" ];
technologies.sort();
jQuery.sap.require("jquery.sap.strings"); // Load the plugin to use
// 'jQuery.sap.startsWithIgnoreCase'
// Help function to filter the technologies according to the given prefix
var filterTechnologies = function(sPrefix) {
var aResult = [];
for (var i = 0; i < technologies.length; i++) {
if (!sPrefix || sPrefix.length == 0
|| jQuery.sap.startsWithIgnoreCase(technologies[i], sPrefix)) {
aResult.push(technologies[i]);
}
}
return aResult;
};
var count = 0;
var arr = [];
// function for add the item to horizontal layout
var addTechnology = function(techName) {
var elementIndex = arr.indexOf(techName);
// conditional statement for adding the tech to the list
if (elementIndex === -1) {
count++;
// create a horizontal Splitter
var oSplitterV = new sap.ui.commons.Splitter({
width : "120px",
height : "30px",
showScrollBars : false,
splitterBarVisible : false
});
oSplitterV.setSplitterOrientation(sap.ui.commons.Orientation.vertical);
oSplitterV.setSplitterPosition("60%");
oSplitterV.setMinSizeFirstPane("60%");
oSplitterV.setMinSizeSecondPane("40%");
// label with dynamic Id
var oLabel1 = new sap.ui.commons.Label("tCount" + count, {
text : techName,
tooltip : techName
});
oSplitterV.addFirstPaneContent(oLabel1);
var oLabel2 = new sap.ui.commons.Button({
icon : "img/delete.png",
press : function() {
removeElement(techName);
oSplitterV.destroy();
}
});
oSplitterV.addSecondPaneContent(oLabel2);
sap.ui.getCore().byId("target").addContent(oSplitterV);
// Adding the tech to the parent array
arr.push(techName);
// Emptying the search box
sap.ui.getCore().byId("suggestSearch1").setValue("");
} else {
sap.ui.commons.MessageBox.alert(techName
+ " is already added to the list");
}
}
// function for removing removed element from parent array
var removeElement = function(addedTech) {
// Find and remove item from an array
var i = arr.indexOf(addedTech);
if (i != -1) {
arr.splice(i, 1);
}
}
Please make a note that I concentrated more on functionality rather than look and feel
Thanks,
prodeveloper

Mvvm with knockout : array binding and changing inner objects state

I have an array in my View Model. Items of this array are objects of Person that has two properties. when I bind this to a template it's okay. but when I change the state of one of the properties it does not reflect in UI.
what did I do wrong ?
<script type="text/html" id="person-template">
<p>Name: <span data-bind="text: name"></span></p>
<p>
Is On Facebook ?
<input type="checkbox" data-bind="checked: IsOnFacebook" />
</p>
</script>
<script type="text/javascript">
var ppl = [
{ name: 'Pouyan', IsOnFacebook: ko.observable(true) },
{ name: 'Reza', IsOnFacebook: ko.observable(false) }
];
function MyViewModel() {
this.people = ko.observableArray(ppl),
this.toggle = function () {
for (var i = 0; i < ppl.length; i++) {
ppl[i].IsOnFacebook = false;
}
}
}
ko.applyBindings(new MyViewModel());
</script>
when I press the button I want to make changes in People.IsOnFacebook property. the changes will be made successfully but the UI does not show.
You should call it like a function. Like:
ppl[i].IsOnFacebook(false);
This because the ko.observable() returns a function. It's not a property you call anymore but a function call. So in the background they will update your UI. To retreive a property that is observable. You should also use the function call.
Please see this tutorial: http://learn.knockoutjs.com/#/?tutorial=intro

Google Autocomplete - enter to select

I have Google Autocomplete set up for a text field of an HTML form, and it's working perfectly.
However, when the list of suggestions appear, and you use the arrows to scroll and select using enter, it submits the form, though there are still boxes to fill in. If you click to select a suggestion it works fine, but pressing enter submits.
How can I control this? How can I stop enter from submitting the form, and instead be the selection of a suggestion from autocomplete?
Thanks!
{S}
You can use preventDefault to stop the form being submitted when enter is hit, I used something like this:
var input = document.getElementById('inputId');
google.maps.event.addDomListener(input, 'keydown', function(event) {
if (event.keyCode === 13) {
event.preventDefault();
}
});
Using the Google events handling seems like the proper solution but it's not working for me. This jQuery solution is working for me:
$('#inputId').keydown(function (e) {
if (e.which == 13 && $('.pac-container:visible').length) return false;
});
.pac-container is the div that holds the Autocomplete matches. The idea is that when the matches are visible, the Enter key will just choose the active match. But when the matches are hidden (i.e. a place has been chosen) it will submit the form.
I've amalgamated the first two answers from #sren and #mmalone to produce this:
var input= document.getElementById('inputId');
google.maps.event.addDomListener(input, 'keydown', function(e) {
if (e.keyCode == 13 && $('.pac-container:visible').length) {
e.preventDefault();
}
});
works perfectly on the page. prevents the form from being submitted when the suggestion container (.pac-container) is visible. So now, an option from the autocomplete dropdown is selected when the users presses the enter key, and they have to press it again to submit the form.
My main reason for using this workaround is because I found that if the form is sent as soon as an option is selected, via the enter key, the latitude and longitude values were not being passed fast enough into their hidden form elements.
All credit to the original answers.
This one worked for me:
google.maps.event.addDomListener(input, 'keydown', e => {
// If it's Enter
if (e.keyCode === 13) {
// Select all Google's dropdown DOM nodes (can be multiple)
const googleDOMNodes = document.getElementsByClassName('pac-container');
// Check if any of them are visible (using ES6 here for conciseness)
const googleDOMNodeIsVisible = (
Array.from(googleDOMNodes).some(node => node.offsetParent !== null)
);
// If one is visible - preventDefault
if (googleDOMNodeIsVisible) e.preventDefault();
}
});
Can be easily converted from ES6 to any browser-compatible code.
The problem I had with #sren's answer was that it blocks the submit event always. I liked #mmalone's answer but it behaved randomly, as in sometimes when I hit ENTER to select the location, the handler ran after the container is hidden. So, here's what I ended up doing
var location_being_changed,
input = document.getElementById("js-my-input"),
autocomplete = new google.maps.places.Autocomplete(input),
onPlaceChange = function () {
location_being_changed = false;
};
google.maps.event.addListener( this.autocomplete,
'place_changed',
onPlaceChange );
google.maps.event.addDomListener(input, 'keydown', function (e) {
if (e.keyCode === 13) {
if (location_being_changed) {
e.preventDefault();
e.stopPropagation();
}
} else {
// means the user is probably typing
location_being_changed = true;
}
});
// Form Submit Handler
$('.js-my-form').on('submit', function (e) {
e.preventDefault();
$('.js-display').text("Yay form got submitted");
});
<p class="js-display"></p>
<form class="js-my-form">
<input type="text" id="js-my-input" />
<button type="submit">Submit</button>
</form>
<!-- External Libraries -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src="//maps.googleapis.com/maps/api/js?sensor=false&libraries=places"></script>
The flag ensures that if the location is being changed & user hits enter, the event is blocked. Eventually the flag is set to false by google map's place_changed event, which then allows the form to be submitted on hitting the enter key.
Here's a simple code that worked well for me (uses no jquery).
const googleAutcompleteField = this.renderer.selectRootElement(this.elem.nativeElement);
this.selectOnEnter(googleAutcompleteField);
This piece of code, to follow the code above, is used to implement google maps autocomplete (with or without the Enter key functionality sought in this question):
this.autocomplete = new google.maps.places.Autocomplete(googleAutcompleteField, this.googleMapsOptions);
this.autocomplete.setFields(['address_component', 'formatted_address', 'geometry']);
this.autocomplete.addListener('place_changed', () => {
this.zone.run(() => {
this.googleMapsData.emit([this.autocomplete.getPlace()]);
})
})
selectOnEnter (called above in the first piece of code) defined:
selectOnEnter(inputField) {
inputField.addEventListener("keydown", (event) => {
const selectedItem = document.getElementsByClassName('pac-item-selected');
if (event.key == "Enter" && selectedItem.length != 0) {
event.preventDefault();
}
})
}
This code makes the google maps autocomplete field select whichever item user selects with the down arrow keypress. Once user selects an option with a press of the Enter key, nothing happens. User has to press Enter again to trigger onSubmit() or other command
You can do it in vanilla :
element.addEventListener('keydown', function(e) {
const gPlaceChoices = document.querySelector('.pac-container')
// No choices element ?
if (null === gPlaceChoices) {
return
}
// Get choices visivility
let visibility = window.getComputedStyle(gPlaceChoices).display
// In this case, enter key will do nothing
if ('none' !== visibility && e.keyCode === 13) {
e.preventDefault();
}
})
I tweaked Alex's code, because it broke in the browser. This works perfect for me:
google.maps.event.addDomListener(
document.getElementById('YOUR_ELEMENT_ID'),
'keydown',
function(e) {
// If it's Enter
if (e.keyCode === 13) {
// Select all Google's dropdown DOM nodes (can be multiple)
const googleDOMNodes = document.getElementsByClassName('pac-container');
//If multiple nodes, prevent form submit.
if (googleDOMNodes.length > 0){
e.preventDefault();
}
//Remove Google's drop down elements, so that future form submit requests work.
removeElementsByClass('pac-container');
}
}
);
function removeElementsByClass(className){
var elements = document.getElementsByClassName(className);
while(elements.length > 0){
elements[0].parentNode.removeChild(elements[0]);
}
}
I've tried the above short answers but they didn't work for me, and the long answers I didn't want to try them, so I've created the following code which worked pretty well for me. See Demo
Suppose this is your form:
<form action="" method="">
<input type="text" name="place" id="google-places-searchbox" placeholder="Enter place name"><br><br>
<input type="text" name="field-1" placeholder="Field 1"><br><br>
<input type="text" name="field-2" placeholder="Field 2"><br><br>
<button type="submit">Submit</button>
</form>
Then the following javascript code will solve the problem:
var placesSearchbox = $("#google-places-searchbox");
placesSearchbox.on("focus blur", function() {
$(this).closest("form").toggleClass('prevent_submit');
});
placesSearchbox.closest("form").on("submit", function(e) {
if (placesSearchbox.closest("form").hasClass('prevent_submit')) {
e.preventDefault();
return false;
}
});
And here is how the full code looks like in the HTML page (Note that you need to replace the YOUR_API_KEY with your google api key):
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>Prevent form submission when choosing a place from google places autocomplete searchbox</title>
</head>
<body>
<form action="" method="">
<input type="text" name="place" id="google-places-searchbox" placeholder="Enter place name"><br><br>
<input type="text" name="field-1" placeholder="Field 1"><br><br>
<input type="text" name="field-2" placeholder="Field 2"><br><br>
<button type="submit">Submit</button>
</form>
<!-- jQuery -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<!-- Google Maps -->
<!-- Note that you need to replace the next YOUR_API_KEY with your api key -->
<script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&libraries=places"
async defer></script>
<script>
var input = document.getElementById("google-places-searchbox");
var searchBox = new google.maps.places.SearchBox(input);
var placesSearchbox = $("#google-places-searchbox");
placesSearchbox.on("focus blur", function() {
$(this).closest("form").toggleClass('prevent_submit');
});
placesSearchbox.closest("form").on("submit", function(e) {
if (placesSearchbox.closest("form").hasClass('prevent_submit')) {
e.preventDefault();
return false;
}
});
</script>
</body>
</html>
$("#myinput").on("keydown", function(e) {
if (e.which == 13) {
if($(".pac-item").length>0)
{
$(".pac-item-selected").trigger("click");
}
}
Use $('.pac-item:first').trigger('click'); if you want to select first result

HTML5 Geolocation data loaded in a form to send towards database

i'm busy with a school project and I have to build a web app. One function that I want to use is Google Maps and HTML5 Geo Location to pin point what the location of the mobile user is.
I have found this HTML5 Geo Location function on http://merged.ca/iphone/html5-geolocation and works very well for me. However, I want the adress data to be placed into a form so that I can submit it to my database when a mobile user Geo locates his position. This causes the marker to be saved and can be viewed on a global website.
Who know how to get the "Your address:" data loaded into a input field of a form?
Below you can find my Html file. Maybe somebody got a better suggestion perhaps?
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<title>HTML 5 Geolocation</title>
<style>
#map {
height:300px;
width:300px;
}
</style>
<script type="text/javascript" src="http://www.google.com/jsapi"></script>
<script type="text/javascript">google.load("jquery", "1"); google.load("jqueryui", "1");</script>
<script src="http://maps.google.com/maps?file=api&v=2&sensor=false&key=ABQIAAAAiUzO1s6QWHuyzxx-JVN7ABSUL8-Cfeleqd6F6deqY-Cw1iTxhxQkovZkaxsxgKCdn1OCYaq7Ubz3SQ" type="text/javascript"></script>
<script type="text/javascript" src="http://api.maps.yahoo.com/ajaxymap?v=3.8&appid=n2wY9mzV34Hsdslq6TJoeoJDLmAfzeBamSwJX7jBGLnjM7oDX7fU.Oe91KwUbOwqzvc-"></script>
<script type="text/javascript">
// Geolocation with HTML 5 and Google Maps API based on example from maxheapsize: http://maxheapsize.com/2009/04/11/getting-the-browsers-geolocation-with-html-5/
//
// This script is by Merge Database and Design, http://merged.ca/ -- if you use some, all, or any of this code, please offer a return link.
var map;
var mapCenter
var geocoder;
var fakeLatitude;
var fakeLongitude;
function initialize()
{
if (navigator.geolocation)
{
navigator.geolocation.getCurrentPosition( function (position) {
// Did we get the position correctly?
// alert (position.coords.latitude);
// To see everything available in the position.coords array:
// for (key in position.coords) {alert(key)}
mapServiceProvider(position.coords.latitude,position.coords.longitude);
}, // next function is the error callback
function (error)
{
switch(error.code)
{
case error.TIMEOUT:
alert ('Timeout');
break;
case error.POSITION_UNAVAILABLE:
alert ('Position unavailable');
break;
case error.PERMISSION_DENIED:
alert ('Permission denied');
break;
case error.UNKNOWN_ERROR:
alert ('Unknown error');
break;
}
}
);
}
else
{
alert("I'm sorry, but geolocation services are not supported by your browser or you do not have a GPS device in your computer. I will use a sample location to produce the map instead.");
fakeLatitude = 49.273677;
fakeLongitude = -123.114420;
//alert(fakeLatitude+', '+fakeLongitude);
mapServiceProvider(fakeLatitude,fakeLongitude);
}
}
function mapServiceProvider(latitude,longitude)
{
if (window.location.querystring['serviceProvider']=='Yahoo')
{
mapThisYahoo(latitude,longitude);
}
else
{
mapThisGoogle(latitude,longitude);
}
}
function mapThisYahoo(latitude,longitude)
{
var map = new YMap(document.getElementById('map'));
map.addTypeControl();
map.setMapType(YAHOO_MAP_REG);
map.drawZoomAndCenter(latitude+','+longitude, 3);
// add marker
var currentGeoPoint = new YGeoPoint( latitude, longitude );
map.addMarker(currentGeoPoint);
// Start up a new reverse geocoder for addresses?
// YAHOO Ajax/JS/Rest API does not yet support reverse geocoding (though they do support it via Actionscript... lame)
// So we'll have to use Google for the reverse geocoding anyway, though I've left this part of the script just in case Yahoo! does support it and I'm not aware of it yet
geocoder = new GClientGeocoder();
geocoder.getLocations(latitude+','+longitude, addAddressToMap);
}
function mapThisGoogle(latitude,longitude)
{
var mapCenter = new GLatLng(latitude,longitude);
map = new GMap2(document.getElementById("map"));
map.setCenter(mapCenter, 15);
map.addOverlay(new GMarker(mapCenter));
// Start up a new reverse geocoder for addresses?
geocoder = new GClientGeocoder();
geocoder.getLocations(latitude+','+longitude, addAddressToMap);
}
function addAddressToMap(response)
{
if (!response || response.Status.code != 200) {
alert("Sorry, we were unable to geocode that address");
} else {
place = response.Placemark[0];
$('#address').html('Your address: '+place.address);
}
}
window.location.querystring = (function() {
// by Chris O'Brien, prettycode.org
var collection = {};
var querystring = window.location.search;
if (!querystring) {
return { toString: function() { return ""; } };
}
querystring = decodeURI(querystring.substring(1));
var pairs = querystring.split("&");
for (var i = 0; i < pairs.length; i++) {
if (!pairs[i]) {
continue;
}
var seperatorPosition = pairs[i].indexOf("=");
if (seperatorPosition == -1) {
collection[pairs[i]] = "";
}
else {
collection[pairs[i].substring(0, seperatorPosition)]
= pairs[i].substr(seperatorPosition + 1);
}
}
collection.toString = function() {
return "?" + querystring;
};
return collection;
})();
</script>
</head>
<body onLoad="initialize()">
<div id="content">
<div id="map"></div>
<p id="address"></p>
<form id="ContactForm" action="">
<p>
<label>Topic</label>
<input id="event" name="event" maxlength="120" type="text" autocomplete="off"/>
</p>
<p>
<label>Address</label>
<input id="address" name="address" maxlength="120" type="text" autocomplete="off"/>
</p>
<input id="send" type="button" value="Send"/>
<input id="newcontact" name="newcontact" type="hidden" value="1"></input>
</form>
</div>
</body>
</html>
You have to use JavaScript to set the value of address input field, this way
1- Add name attribute to the form and input.
2- document.formName.inputName.value=place.address;
Good Luck