How to use variables in _hyperscript js - hyperscript

I'm having fun with _hyperscript js which I find very promising and amusing.
Now I'm trying to understand the use of variables inside simple commands. Suppose that I have the following code generated by a PHP script that queried a dB and where ids are obtained the dB (a very common case):
<div id="1000">Mercedes</div>
<div id="1022">Audi</div>
<div id="1301">Ferrari</div>
<div id="1106">Lamborghini</div>
To add a class to a specific id I would normally do like this:
<button _="on click add .green to #1022" type="button">
Click
</button>
But what if I don't know the id because it's the result of a dB query? How can I place a variable using _hyperscript and set it with javascript? Something like this:
<button _="on click call setID() then add .green to ???" type="button">
Click
</button>
<script type="text/javascript">
function setID() {
// here the code to get the ID
return id;
}
</script>
Using the 'symbol' it to read the result of the last call returns error:
_="on click call setID() then add .green to it"
returns
Uncaught TypeError: target.classList is undefined

You can use string templates inside query literals, so something like this should work:
<button _="on click add .green to <#${getIdToAddTo()}/>" type="button">
Click
</button>
where the <.../> is the query literal and the ${getIdToAddTo()} is a string template within that query
Another alternative would be to create a method that returns the div to add to:
<script>
function divToAddTo() {
return document.getElementById("whatever");
}
</script>
<button _="on click add .green to divToAddTo()" type="button">
Click
</button>

Related

geb cant find checkbox element

there is this piece of code that provides a checkbox following from a link to the T&C.
<div class="checkbox accept_agreement">
<label class="control-label" for="step_data_accept_agreement">
<input type="hidden" name="step_data[accept_agreement]" value="0">
<input type="checkbox" name="step_data[accept_agreement]" id="step_data_accept_agreement" value="1">
<label for="step_data_accept_agreement">
<a target="_blank" href="/lanevillkor/">
<font><font>I agree, have read and stored the terms and conditions</font></font>
</a>
</label>
</label>
</div>
Now, I am working on a spock test using geb, and I try to retrieve the checkbox element
<input type="checkbox" name="step_data[accept_agreement]" id="step_data_accept_agreement" value="1">
to do so i have tried many things without the expected output. i was expected that something like
$("#step_data_accept_agreement").click() would be pretty straight forward but it is not. in the other side if I put $("[for='step_data_accept_agreement'] label").click() it clicks the link.
I tried to become as more specific but nothing looks to return the element correctly.
one of my last attempts was
termsAndConditionsOption(wait: true) { $("#step_data_accept_agreement", name: "step_data[accept_agreement]") }
and the error message, as in the other cases too, was in one sentence
element not visible
What do I miss?
So the solution was to use js to click the checkbox. The simpliest way is:
def agreeOnTermsAndConditionsAccept() {
String mouseClickEvt = """
var evt = new MouseEvent('click', {
bubbles: true,
cancelable: true,
view: window
});
arguments[0].dispatchEvent(evt);
"""
browser.js.exec(termsAndConditionsOption.firstElement(), mouseClickEvt)
}
Geb provides js support to work with javascript, as we find in the documentation. Also another link shows how to simulate a click event with pure javascript.
This was required as the checkbox cant be found as it is hidden. With javascript we can 'see' the position of the element and perform an action in the location that we want. iniMouseEvent can be used as well as it is documentanted here

App script doesn't update the google spreadsheet cell values always

I am using html code to create a dashboard where user can select a date and then based on selected date fetch some values from remote APIs and then show these values in the sheet.
I have html file something like:
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="//code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css">
<script src="//code.jquery.com/jquery-1.10.2.js"></script>
<script src="//code.jquery.com/ui/1.11.4/jquery-ui.js"></script>
<link rel="stylesheet" href="/resources/demos/style.css">
<script>
$(function() {
$( "#datepicker" ).datepicker();
});
</script>
</head>
<body>
<form>
<select name="Student" id="category">
<option value="" selected="selected">Select Student</option>
<option value="Abercrombie, Amber">Abercrombie, Amber(Gr 11)</option>
<option value="Yupa, Jason">Yupa, Jason(Gr 9)</option>
</select>
Date: <input type="text" id="datepicker" name="datepicker">
<input type="submit" value="Submit" onclick="myFunction()">
</form>
<p id="demo"></p>
<script>
function myFunction() {
var x = document.getElementById("category").value;
var x2 = document.getElementById("datepicker").value;
//document.getElementById("demo").innerHTML = x;
google.script.run.functionToRunOnFormSubmit(x, x2);
google.script.host.close();
}
</script>
</body>
</html>
I have code.gs as follows:
function fncOpenMyDialog() {
//Open a dialog
var htmlDlg = HtmlService.createHtmlOutputFromFile('HTML_myHtml')
.setSandboxMode(HtmlService.SandboxMode.IFRAME)
.setWidth(500)
.setHeight(300);
SpreadsheetApp.getUi()
.showModalDialog(htmlDlg, 'Dashboard');
};
function functionToRunOnFormSubmit(fromInputForm, datevalue) {
Logger.log(fromInputForm);
Logger.log(datevalue);
SpreadsheetApp.getActiveSheet().getRange('B3').setValue(fromInputForm);
SpreadsheetApp.getActiveSheet().getRange('B4').setValue(datevalue);
};
When I select the function(fncOpenMyDialog()) from script-editor, It create a dashboard on the spreadsheet, Where I am able to select the date but as in functionToRunOnFormSubmit function I am logging the argument and then correspondingly setting the B3 and B4 cell values. It is not getting updated also It is not getting logged in the script editor.
The problem is you are calling "close" right after calling the google.script.run function which is an asynchronous ajax call.
In some cases it likely doesnt even give the browser enough time to start the ajax call or it gets cancelled because the page is closing. So sometimes it might reach the backend script, and sometimes wont.
take a look at the documentation and handle both success (close dialog from there) and failure (show error to the user)
https://developers.google.com/apps-script/guides/html/reference/run
While the documentation doesnt show it explicitly, you can hook both calls like this:
google.script.run.withFailureHandler(onFailure).withSuccessHandler(onSuccess).yourCall();

additional text fields in html form after a numeric entry in another text field

Am using an html form to send data to a sql database using php.
My trouble is that I have a dynamic value for number of items which changes for each order and am trying to avoid having to add an x number of extra text fields for all orders.
A better solution would be to enter a value in a text field which then makes the same number of additional text fields appear in the form.
Is there anyway to accomplish this?
Thanks
OK. So you want to show a number of input fields at the user's request, before pressing the submit button. My first approach would be to do it in javascript.
Let's assume this form:
<form>
<p><input name="myInput1" /></p>
<button type="submit">submit</button>
</form>
You could include an extra button to add a new row:
<form>
<p><input name="myInput1" /></p>
<button type="button" onclick="addInput(this.form)">add input</button>
<button type="submit">submit</button>
</form>
... and the handler function would be something like this:
<script type="text/javascript">
function addInput(form)
{
// Create a new <p><input> node at the end of the form, throughput the DOM API:
// Get the last <p> element of the form
var paragraphs=form.getElementsByTagName("P")
var lastParagraph=paragraphs[paragraphs.length-1]
// Create a new <p> element with a <input> child:
var newParagraph=document.createElement("P")
var newInput=document.createElement("INPUT")
// Name the <input> with a numeric suffix not to produce duplicates:
newInput.name="myInput"+(1+paragraphs.length)
newParagraph.appendChild(newInput)
// Add the created <p> after the last existing <p> of the form:
form.insertBefore(newParagraph, lastParagraph.nextSibling)
}
</script>
(Notice that all the rendering logic is performed in the client side (in HTML + javascript), and when the form is finally submitted, the server will just receive a collection of pairs name + value.)

meteor-typeahead: Listing and selecting

I have installed meteor-typeahead via npm. https://www.npmjs.org/package/meteor-typeahead
I have also installed
meteor add sergeyt:typeahead
from https://atmospherejs.com/sergeyt/typeahead
I am trying to get the data-source attribute example to function so I can display a list of countries when the user begins to type. I have inserted all countries into the collection :-
Country = new Meteor.Collection('country');
The collection is published and subscribed.
When I type into the input field, no suggestions appear. Is it something to do with activating the API? if so how do I do this? Please reference the website https://www.npmjs.org/package/meteor-typeahead
My form looks like this:
<template name="createpost">
<form class="form-horizontal" role="form" id="createpost">
<input class="form-control typeahead" name="country" type="text" placeholder="Country" autocomplete="off" spellcheck="off" data-source="country"/>
<input type="submit" value="post">
</form>
</template>
client.js
Template.createpost.helpers({
country: function(){
return Country.find().fetch().map(function(it){ return it.name; });
} });
In order to make your input to have typeahead completion you need:
Activate typeahead jQuery plugin using package API
Meteor.typeahead call in template rendered event handler.
Meteor.typeahead.inject call to activate typeahead plugin for elementes matched by CSS selector available on the page (see demo app).
Write 'data-source' function in your template understandable by typeahead plugin. It seems your 'data-source' function is correct.
Add CSS styles for typeahead input(s)/dropdown to your application. See example here in demo app.
Try this way in your template:
<input type="text" name="country" data-source="country"
data-template="country" data-value-key="name" data-select="selected">
Create template like country.html (for example /client/templates/country.html) which contains:
<template name="country">
<p>{{name}}</p>
</template>
In your client javascript:
Template.createpost.rendered = function() {
Meteor.typeahead.inject();
}
and
Template.createpost.helpers({
country: function() {
return Country.find().fetch().map(function(it){
return {name: it.name};
});
},
selected: function(event, suggestion, datasetName) {
console.log(suggestion); //or anything what you want after selection
}
})

Rendering new div created dynamically with Meteor

I have a the classic "Thread->Posts" model.
In the application, I have a left sidebar with the "Thread" collections. When the user click in a Thread, I want to create another div with the Thread->Posts elements.
Is there any way to do this, conservating the reactivity?
For now, I've got this:
// In the client
Template.threadlist.events({
'click tr': function(event){
Session.set("selectedThread",this);
$("#posts").html( Meteor.render(Template["datathread"]) );
}
})
[...]
Template.datathread.events({
'click input.add-post' : function(event){
var t = Session.get("selectedThread");
Meteor.call("addPost", {"thread":t,"text":"foo","user":"var"},callback})
}
})
[...]
// In the server
addPost: function(param){
var id = Threads.update(param.thread,{ $addToSet: {"posts": {"text":param.text, "user": param.user}}});
return id;
}
The template with the posts is something like this:
<template name="datathread">
{{#each thread.posts}}
{{user}} says: {{text}}
<br />
{{/each}}
</template>
(The "user" and "text" propertis are from the "thread.posts" elements)
With this code, I only get the new values refreshing (F5) the webpage (or executing the 'click tr'event). What I'm doing wrong?
Thank you!
== Edit ==
Ok... Now, with the recomendation of Chistian Fritz, my code its something like this:
// In the client
Template.datathread.thread = function(){
return Session.get("selectedThread");
}
[...]
Template.threadlist.events({
'click tr': function(event){
Session.set("selectedThread",this);
}
});
//In the html
<div class="span5" id="threads">
{{> datathread}}
</div>
<template name="datathread">
{{#if thread}}
<hr />
{{#each thread.posts}}
{{user}} says: {{text}}
<br />
{{/each}}
{{/if}}
</template>
The changes are great (it's so simple!), but the reactivity still doesn't work :(....
The problem is that you are using jQuery to fill your DOM:
$("#posts").html( Meteor.render(Template["datathread"]) );
This breaks the reactivity chain.
You are only showing part of your code, so I can't give you the full solution, but it seems that the datathread template is already using the selectedThread session variable -- which is good. Hence, it might be as easy as using {{> datathread}} in place of the #posts element in your HTML.
EDIT:
One thing that you need to change is the scope you are assuming datathread: it's already the thread itself, if I understand correctly:
<template name="datathread">
<hr />
{{#each posts}}
{{user}} says: {{text}}
<br />
{{/each}}
</template>
Also, the this in the threadlist event handler most certainly won't be the thread. I don't know the data of the tr in the threadlist (can you show that code?), but you will most probably do something like the following:
Session.set("selectedThread", this.id);
And for datathread:
Template.datathread.thread = function(){
return Threads.find({_id: Session.get("selectedThread")});
}
or similar.

Resources