I wondering if there is a way to get the api to inform me when a ferry is taken. I know you can change avoidFerries: between true and false, but when set as true I need a way of knowing the ferry has been taken so I can override if necessary via an external button. I just need a way of getting gMaps to tell me one has been taken. Any suggestions would be greatly appreciated.
Regards.
You must parse the steps of a route.
When a step takes a ferry it depends on the TravelMode how to detect it.
For TRANSIT you have to check:
step.transit.line.vehicle.type==='FERRY'
for other TravelModes it would be:
step.maneuver==='ferry'
A function to detect it may look like this:
/**
* #param route object DirectionsRoute
* #return array with steps where a ferry has been taken
**/
function get_ferries(route){
var f=[],section;
for(var leg=0;leg<route.legs.length;++leg){
for(var step=0;step<route.legs[leg].steps.length;++step){
section = route.legs[leg].steps[step];
if(
section.maneuver==='ferry'
||
(
section.transit
&&
section.transit.line
&&
section.transit.line.vehicle
&&
section.transit.line.vehicle.type==='FERRY'
)
){
f.push(section);
}
}
}
return f;
}
Demo:
function initMap() {
var goo = google.maps,
service = new goo.DirectionsService,
map = new goo.Map(document.getElementById('map'), {
zoom: 0,
center: {lat: 0, lng: 0},
noClear:true
}),
renderer = new goo.DirectionsRenderer({suppressMarkers:true,map:map,polylineOptions:{strokeWeight:3,zIndex:100}}),
ctrl = document.getElementById('ctrl'),
sMode = ctrl.querySelector('select[name="mode"]'),
sRoute = ctrl.querySelector('select[name="route"]')
sFerry = ctrl.querySelector('select[name="ferries"]')
calcRoute = function(){
var mode = goo.TravelMode[sMode.value],
avoidFerries = !!parseInt(sFerry.value),
route = sRoute.options[sRoute.selectedIndex],
origin = route.getAttribute('data-origin'),
destination = route.getAttribute('data-destination');
map.data.forEach(function(f){
map.data.remove(f);
});
service.route({
origin : origin,
destination : destination,
travelMode : mode,
avoidFerries: avoidFerries
}, function(response, status) {
renderer.setDirections(response);
if (status !== goo.DirectionsStatus.OK) {
alert('Directions request failed due to ' + status);
}
});
};
map.data.setStyle({
strokeColor: 'tomato',
strokeWeight: 5,
strokeOpacity: 1,
zIndex:1000,
icon: 'https://maps.gstatic.com/mapfiles/transit/iw2/6/ferry.png'
});
map.controls[google.maps.ControlPosition.TOP_CENTER].push(ctrl);
goo.event.addDomListener(sMode, 'change', calcRoute);
goo.event.addDomListener(sRoute, 'change', calcRoute);
goo.event.addDomListener(sFerry, 'change', calcRoute);
goo.event.addListener(renderer,'directions_changed',function(){
var r= this.getDirections(),
i= this.getRouteIndex();
if(r && r.routes && r.routes[i]){
var ferries=get_ferries(r.routes[i]);
if(ferries.length){
alert('Ferries:'+ ferries.length);
for(var f=0;f<ferries.length;++f){
map.data.add({geometry:ferries[f].start_location})
map.data.add({geometry:new goo.Data.LineString(ferries[f].path)})
}
}
}
});
function get_ferries(route){
var f=[],section;
for(var leg=0;leg<route.legs.length;++leg){
for(var step=0;step<route.legs[leg].steps.length;++step){
section = route.legs[leg].steps[step];
if(
section.maneuver==='ferry'
||
(
section.transit
&&
section.transit.line
&&
section.transit.line.vehicle
&&
section.transit.line.vehicle.type==='FERRY'
)
){
f.push(section);
}
}
}
return f;
}
calcRoute();
}
html,
body,
#map {
height: 100%;
margin: 0;
padding: 0;
}
<div id="map">
<div id="ctrl">
<select name="route">
<option data-origin="Rostock,DE" data-destination="Bornholm,DK">Rostock-Bornholm</option>
<option data-origin="Rotterdam,NL" data-destination="Ipswich,UK">Rotterdam-Ipswich</option>
<option data-origin="Manhattan,US" data-destination="Ellis Island,US">Manhattan-Ellis Island</option>
</select>
<select name="mode">
<option value="DRIVING">Driving</option>
<option value="TRANSIT">Transit</option>
<option value="WALKING">Walking</option>
<option value="BICYCLING">Bicycling</option>
</select>
<select name="ferries">
<option value="0">avoidFerries:no</option>
<option value="1">avoidFerries:yes</option>
</select>
</div>
</div>
<script src="https://maps.googleapis.com/maps/api/js?v=3&callback=initMap" async defer></script>
Related
I have a very simple pug file:
for item in itemList
form(method='post', action='/change')
table
tr
td(width=100)
td(width=200)
| #{item.name}
input(type='hidden', name='field' value=item.name)
input(type='hidden', name='style' value='doublevalue')
td(width=100)
input(type='number', name='value' min=-20.0 max=80.00 step=0.01 value=+item.value)
td(width=100)
input(type='submit', value='Update')
p end
As you can see it produces a few trivial forms like this:
(Each form is one 'line' which is a simple table.)
(On the script side, it just reads each 'line' from a MySQL table, there are 10 or so of them.)
So on the www page, the user either
types in new number (say "8")
or clicks the small arrows (say Up, changing it to 7.2 in the example)
then the user must
click submit
and it sends the post.
Quite simply, I would like it to be that when the user
clicks a small arrows (say Up, changing it to 7.2 in the example)
it immediately sends a submit-post.
How do I achieve this?
(It would be fine if the send happens, any time the user types something in the field, and/or, when the user clicks the Small Up And Down Buttons. Either/both is fine.)
May be relevant:
My pug file (and all my pug files) have this sophisticated line of code as line 1:
include TOP.pug
And I have a marvellous file called TOP.pug:
html
head
style.
html {
font-family: sans-serif
}
td {
font-family: monospace
}
body
I have a solution with javascript.
// check if there are input[type="number"] to prevent errors
if (document.querySelector('input[type="number"]')) {
// add event for each of them
document.querySelectorAll('input[type="number"]').forEach(function(el) {
el.addEventListener('change', function (e) {
// on change submit the parent (closest) form
e.currentTarget.closest('form').submit()
});
});
}
Actually it is short but if you want to support Internet Explorer you have to add the polyfill script too. Internet Explorer does not support closest() with this snippet below we teach it.
// polyfills for matches() and closest()
if (!Element.prototype.matches)
Element.prototype.matches = Element.prototype.msMatchesSelector || Element.prototype.webkitMatchesSelector;
if (!Element.prototype.closest) {
Element.prototype.closest = function(s) {
var el = this;
do {
if (el.matches(s)) return el;
el = el.parentElement || el.parentNode;
} while (el !== null && el.nodeType === 1);
return null;
};
}
Ajax form submit to node.js
If you are interested in an ajax solution I put some code below just to blow your mind ;-) It should work instantly, I use it on one of my sites. You could use jQuery and save lines of code but I like it pure. (The ajax function and polyfills are utils so paste it anywhere)
HTML (example)
<form>
<input type="hidden" name="field" value="field1">
<input type="hidden" name="style" value="style1">
<input type="number" name="value">
<input type="submit" value="update">
</form>
<form>
<input type="hidden" name="field" value="field2">
<input type="hidden" name="style" value="style2">
<input type="number" name="value">
<input type="submit" value="update">
</form>
Javascript: event listener and prepare ajax call (note the callbacks).
// check if there are forms to prevent errors
if (document.querySelector('form')) {
// add submit event for each form
document.querySelectorAll('form').forEach(function (el) {
el.addEventListener('submit', function (e) {
e.currentTarget.preventDefault();
submitData(e.currentTarget);
});
});
}
// check if there are input[type="number"] to prevent errors
if (document.querySelector('input[type="number"]')) {
// add change event for each of them
document.querySelectorAll('input[type="number"]').forEach(function (el) {
el.addEventListener('change', function (e) {
submitData(e.currentTarget.closest('form'));
});
});
}
// collect form data and send it
function submitData(form) {
// send data through (global) ajax function
ajax({
url: '/change',
method: 'POST',
data: {
field: form.querySelector('input[name="field"]').value,
style: form.querySelector('input[name="style"]').value,
value: form.querySelector('input[name="value"]').value,
},
// callback on success
success: function (response) {
// HERE COMES THE RESPONSE
console.log(response);
// error is defined in (node.js res.json({error: ...}))
if (response.error) {
// make something red
form.style.border = '1px solid red';
}
if (!response.error) {
// everything ok, make it green
form.style.border = '1px solid green';
}
// remove above styling
setTimeout(function () {
form.style.border = 'none';
}, 1000);
},
// callback on error
error: function (error) {
console.log('server error occurred: ' + error)
}
});
}
As told javascript utils (paste it anywhere like a library)
// reusable ajax function
function ajax(obj) {
let a = {};
a.url = '';
a.method = 'GET';
a.data = null;
a.dataString = '';
a.async = true;
a.postHeaders = [
['Content-type', 'application/x-www-form-urlencoded'],
['X-Requested-With', 'XMLHttpRequest']
];
a.getHeaders = [
['X-Requested-With', 'XMLHttpRequest']
];
a = Object.assign(a, obj);
a.method = a.method.toUpperCase();
if (typeof a.data === 'string')
a.dataString = encodeURIComponent(a.data);
else
for (let item in a.data) a.dataString += item + '=' + encodeURIComponent(a.data[item]) + '&';
let xhReq = new XMLHttpRequest();
if (window.ActiveXObject) xhReq = new ActiveXObject('Microsoft.XMLHTTP');
if (a.method == 'GET') {
if (typeof a.data !== 'undefined' && a.data !== null) a.url = a.url + '?' + a.dataString;
xhReq.open(a.method, a.url, a.async);
for (let x = 0; x < a.getHeaders.length; x++) xhReq.setRequestHeader(a.getHeaders[x][0], a.getHeaders[x][1]);
xhReq.send(null);
}
else {
xhReq.open(a.method, a.url, a.async);
for (let x = 0; x < a.postHeaders.length; x++) xhReq.setRequestHeader(a.postHeaders[x][0], a.postHeaders[x][1]);
xhReq.send(a.dataString);
}
xhReq.onreadystatechange = function () {
if (xhReq.readyState == 4) {
let response;
try {
response = JSON.parse(xhReq.responseText)
} catch (e) {
response = xhReq.responseText;
}
//console.log(response);
if (xhReq.status == 200) {
obj.success(response);
}
else {
obj.error(response);
}
}
}
}
// (one more) polyfill for Object.assign
if (typeof Object.assign !== 'function') {
// Must be writable: true, enumerable: false, configurable: true
Object.defineProperty(Object, 'assign', {
value: function assign(target, varArgs) {
// .length of function is 2
if (target === null || target === undefined) {
throw new TypeError('Cannot convert undefined or null to object');
}
var to = Object(target);
for (var index = 1; index < arguments.length; index++) {
var nextSource = arguments[index];
if (nextSource !== null && nextSource !== undefined) {
for (var nextKey in nextSource) {
// Avoid bugs when hasOwnProperty is shadowed
if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {
to[nextKey] = nextSource[nextKey];
}
}
}
}
return to;
},
writable: true,
configurable: true
});
}
// polyfills for matches() and closest()
if (!Element.prototype.matches)
Element.prototype.matches = Element.prototype.msMatchesSelector || Element.prototype.webkitMatchesSelector;
if (!Element.prototype.closest) {
Element.prototype.closest = function (s) {
var el = this;
do {
if (el.matches(s)) return el;
el = el.parentElement || el.parentNode;
} while (el !== null && el.nodeType === 1);
return null;
};
}
In node.js (e.g. express route)
// the route in node.js
app.post('/change', (req, res) => {
// your logic here
let field = req.body.field;
let style = req.body.style;
let value = req.body.value;
// ...
// response result
res.json({
databaseError: false, // or true
additionalStuff: 'message, markup and other things ...',
});
});
I am using Alfresco selectone.ftl to customize a dropdown list. I do not want to show any blank option as default. But the Selectone.ftl automatically adds a blank option. How to set my value as the default and delete the blank option.
There is Requirement where i have to display list of user in dropdown base on some condition , for that i have customize selectone.ftl as per below code,may be helpful to you.
** This is custom-selectone.ftl**
<div class="form-field">
<script type="text/javascript">//<![CDATA[
YAHOO.util.Event.onAvailable("${fieldHtmlId}", function(){
new selectAjax("${fieldHtmlId}");
});
function selectAjax(currentValueHtmlId) {
this.currentValueHtmlId = currentValueHtmlId;
var select = Dom.get(this.currentValueHtmlId);
this.register = function () {
Alfresco.util.Ajax.jsonGet({
url: Alfresco.constants.PROXY_URI+"userwebsacript",
successCallback: {
fn: this.updateOptions,
scope: this
},
failureCallback: {
fn: function(){},
scope: this
}
});
};
this.updateOptions = function (res) {
var result = res.serverResponse.responseText;
if (result.length > 0) {
var sp=result.split(",");
for(var i=0;i<sp.length;i++){
var option = new Option(sp[i], sp[i]);
select.options[select.options.length] = option;
}
}
};
this.register();
}
//]]></script>
<label for="${fieldHtmlId}">${field.label?html}:<#if field.mandatory><span class="mandatory-indicator">${msg("form.required.fields.marker")}</span></#if></label>
<select id="${fieldHtmlId}" name="${field.name}" tabindex="0"
<#if field.description??>title="${field.description}"</#if>
<#if field.control.params.size??>size="${field.control.params.size}"</#if>
<#if field.control.params.styleClass??>class="${field.control.params.styleClass}"</#if>
<#if field.control.params.style??>style="${field.control.params.style}"</#if>
<#if field.disabled && !(field.control.params.forceEditable?? && field.control.params.forceEditable == "true")>disabled="true"</#if>>
<option value="">Select</option>
</select>
I have an edit form that is bound to existing data. I have two dropdowns that I would like have update each up depending on specific criteria. For example, is I set the assignedTo to blank, change the status to UnAssigned, and/or if I change the status to UnAssigned, change the AssignedTo to be blank, etc.
Status Dropdown:
<select class="form-control edit-status" id="status" name="status">
<option selected="{{equals status 'UnAssigned'}}" value="UnAssigned">UnAssigned</option>
<option selected="{{equals status 'Open w Vendor'}}" value="Open w Vendor">Ticket with Vendor</option>
<option selected="{{equals status 'Not Started'}}" value="Not Started">Not Started</option>
<option selected="{{equals status 'In Progress'}}" value="In Progress">In Progress</option>
<option selected="{{equals status 'Reopened'}}" value="Reopened">Reopened</option>
</select>
Assigned To Dropdown
<select class="form-control edit-assigned-to" id="assignedTo" name="assignedTo">
<option value="" selected="{{equals assignedTo ''}}">Select a User</option>
{{#each users}}
<option value="{{_id}}" selected="{{equals ../assignedTo _id}}">{{services.auth0.name}}</option>
{{/each}}
</select>
I already have an equality helper on each of them to pick the value that is already set when loading the form data. I was thinking of using Reactive Vars with change events, but I'm unsure how to exactly to implement that or if I'm even on the right track. T
Let's say the collection that contains the status and assignedTo fields is called myCollection:
Template.myTemplate.events({
'change #status': function(ev){
ev.stopPropagation();
var newStatus = $('#status).val();
if ( newStatus == "UnAssigned" ){ // unset the assignedTo value
myCollection.update({ _id: this._id },
{ $set: { status: newStatus}, $unset: { assignedTo: true }});
} else {
myCollection.update{ _id: this._id },{ $set: { status: newStatus}});
}
},
'change #assignedTo': function(ev){
ev.stopPropagation();
var newAssignedTo = $('#assignedTo').val();
if ( newAssignedTo != "None" ){
var userId = Meteor.users.findOne({ _id: newAssignedTo });
myCollection.update({ _id: this._id },{ $set: { assignedTo: newAssignedTo }});
} else { // unset the assignedTo
myCollection.update({ _id: this._id },
{ $set: { status: "UnAssigned" }, $unset { assignedTo: true }});
}
}
});
Note that in your template you're missing a way to select "None" as a value for the assigned user.
I ended up using some jquery in my change events.
'change .edit-status': function(event, template){
var status = event.target.value;
if (status === "UnAssigned") {
$(".edit-assigned-to").val("");
}
return false;
},
'change .edit-assigned-to': function(event, template){
var assignedTo = event.target.value;
if (!template.data.assignedTo && assignedTo !== "") {
$(".edit-status").val("Not Started");
}
if (assignedTo === "") {
$(".edit-status").val("UnAssigned");
}
return false;
}
I'm not sure if there are better approaches or pitfalls to this solution, but it seems to be meeting my needs.
I have a form in weather that would have had the condition User add as many lines he needs. He clicks a button and an input is added below the other.
I can do this using jQuery, but I would prefer to use the resources of Meteor. Is it possible to do?
Yes it is, here is an example from one of my apps using the underscore package
In the main template:
<template name="ask">
{{#each answerArray}}
{{>answer}}
{{/each}}
<button id="addItem">Add item</button>
</template>
<template name="answer">
<div class="input-group pt10">
<input class="form-control answer" maxlength="30" placeholder="Answer (max 30 chars)" name="answer" />
<span class="input-group-btn">
<button class="btn btn-danger delButton" id="{{id}}" data-id="{{id}}" type="button">Delete</button>
</span>
</div>
</template>
In the js file:
Template.ask.created = function () {
Session.set('action', 'ask');
answerArray = [ //adding at least two items but it could also be empty
{
id: Random.id(), //using this to give an unique id to the control
value: ''
},
{
id: Random.id(),
value: ''
}
];
Session.set('answerArr', answerArray);
}
And the click event:
Template.ask.events = {
'click #addItem': function () {
var answerArray = Session.get('answerArr');
answerArray.push({
id: Random.id() //just a placeholder, you could put any here
});
Session.set('answerArr', answerArray);
}
}
And finally the helper:
Template.ask.helpers({
answerArray: function () {
var answerArray = Session.get("answerArr")
while (answerArray.length < 2) { //i chose to have it between 2 and 6, you can remove these
answerArray.push({
id: Random.id()
})
}
while (answerArray.length > 6) { // maximum
answerArray.pop();
}
Session.set('answerArr', answerArray);
return answerArray;
}
}
This will reactively increase the number of inputs. After that, if you want to process the inputs you could do the following, on a submit form event or button click:
'click #saveQ': function (e) {
e.preventDefault();
var arr = [];
_.each($('.answer'), function (item) {
if ($(item).val() != '')
arr.push({
answer: $(item).val(), //this you customize for your own purposes
number: 0
})
});
And also if you want to delete an input from the page you can use:
Template.answer.events = {
'click .delButton': function (e) {
var thisId = $(e.target).attr("id");
var answerArray = Session.get('answerArr');
var filteredArray = _.filter(answerArray, function (item) {
return item.id != thisId;
});
Session.set('answerArr', filteredArray);
}
}
I need to know about to get array data of collections using Meteor JS. I did a simple example with insert data to collections in Meteor JS as shown below :
if (Hcare_Fileds.find().count() === 0) {
var fieldData = [
{fieldName: "Hcare1",
fieldOptions: [ "Bike","Car","TV","Radio","etc"]
},
{fieldName: "Hcare2",
fieldOptions: [ "Bike1","Car1","TV1","Radio1","etc"]
},
{fieldName: "Hcare3",
fieldOptions: [ "Bike2","Car2","TV2","Radio2","etc"]
}
];
for (var i = 0; i < fieldData.length; i++)
{
var list_id = Hcare_Fileds.insert({fieldname: fieldData[i].fieldName,fieldoptions: fieldData[i].fieldOptions}
, function( error, result)
{
if ( error ) console.log ( "Error :"+error.reason ); //info about what went wrong
if ( result )
{
console.log ( "Success="+result );//the _id of new object if successful
}
});
}
}
And Access the above collection fieldoption array data sa shown below :
{{#each fieldName}}
<div class="fmenu {{isselected}}"> {{ fieldname }} </div>
<div class="foptions">
{{#if isselected}}
{{ fieldoptions }}
// Here get fieldoptions data when selected filedname as Bike,Car,Tv,Radio,etc but i need to return like as array but it returns string
{{/if}}
</div>
{{/each}}
JS Code :
if (Meteor.isClient)
{
Session.set('currentFieldName', '');
Template.main.fieldName = function ()
{
return Hcare_Fileds.find().fetch();
};
//TODO ::
Template.main.events
({
'click .fmenu': function (e,t)
{
// template data, if any, is available in 'this'
if (typeof console !== 'undefined')
console.log("You pressed the button"+this.fieldname);
e.preventDefault();
Session.set('currentFieldName', this.fieldname);
}
});
Template.main.isselected = function ()
{
console.log("currentFieldName");
return Session.equals("currentFieldName", this.fieldname) ? "selected" : '';
};
}
I need to get data as array not string like Bike,Car,Tv,Radio,etc. I didn't get any idea about this.So Can you please suggest me what to do?