Form submission then send an xAPI statement - tin-can-api

I am trying to send an xAPI statement after someone submits a their full name and email address through a form. In addition to sending the statement I would like to display a video.html page whereby they can watch a video. I know that there is an example of this on GitHub but I'm trying to do a much simpler example on my own. Can someone have a look at my attempt below and tell me why it is not working. Thanks very much.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="js/xapiwrapper.min.js"></script>
<script type="text/javascript">
var button = document.getElementById("theButton"),
fullName = button.form.fullNameID.value;
emailAddress = button.form.emailAddressID.value;
button.onclick = function() {
var stmt = new ADL.XAPIStatement(
new ADL.XAPIStatement.Agent(ADL.XAPIWrapper.hash('mailto:emailAddress'), 'fullName'),
new ADL.XAPIStatement.Verb('http://adlnet.gov/expapi/verbs/registered', 'registered'),
new ADL.XAPIStatement.Activity('act:http://ISO9000Video.html', 'Preparing for the ISO 9000 Audit',
'Preparation steps for the upcoming ISO 9000 audit.')
);
stmt.generateId();
stmt.addOtherContextActivity( new ADL.XAPIStatement.Activity('compId:internet_proficiency') );
stmt.generateRegistration();
ADL.XAPIWrapper.changeConfig({
'endpoint': 'https://lrs.adlnet.gov/xapi/',
'user': 'xapi-tools',
'password': 'xapi-tools',
});
ADL.XAPIWrapper.sendStatement(stmt);
var o = document.getElementById('output');
o.innerText = JSON.stringify(stmt, null, ' ');
}
</script>
</head>
<body>
<form id="frm1" action="">
Full Name: <input type="text" id="fullNameID" name="fullName"><br>
Email: <input type="text" id="emailAddressID" name="emailAddress"><br><br>
<input type="button" id="theButton" value="Submit">
</form>
<p>
<code><pre id='output'></pre></code>
</p>
</body>
</html>

Your script at the top of the page is being executed when the page loads, but the form element with the button hasn't been set as the property of the button yet because that part of the DOM hasn't been parsed. If you check the console in your browser you'll see an error such as:
Uncaught TypeError: Cannot read property 'form' of null
Move the <script> block that is currently in the <head> to the bottom of the <body> and it should work.

Related

Unable to Programmatically invoke the invisible recaptcha challenge by ID

We have a set up with multiple forms on a single page. We are rendering each recaptcha successfully, however I'm struggling to invoke the recaptcha challenge programatically targeted to an ID.
Looking at the docs (https://developers.google.com/recaptcha/docs/invisible#programmatic_execute) my understanding is that I can pass an ID with the execute command so the response is filled into g-response within the correct form, otherwise the response defaults to the first g-response it finds on the page (which is no good for anything other than the first form on the page).
I've tried it with a slightly modified version of Googles own example, however we get the error message 'Invalid site key or not loaded in api.js: recaptcha123' even though the key is correct.
Does anyone have any idea how we might get this working?
<html>
<head>
<script>
function onSubmit(token) {
alert('thanks ' + document.getElementById('field').value);
}
function validate(event) {
event.preventDefault();
if (!document.getElementById('field').value) {
alert("You must add text to the required field");
} else {
grecaptcha.execute('recaptcha123');
}
}
function onload() {
var element = document.getElementById('submit');
element.onclick = validate;
}
</script>
<script src="https://www.google.com/recaptcha/api.js" async defer></script>
</head>
<body>
<form>
Name: (required) <input id="field" name="field">
<div id="recaptcha123" class="g-recaptcha"
data-sitekey="XXXXXXXXXXXXXXXX"
data-callback="onSubmit"
data-size="invisible"></div>
<button id="submit">submit</button>
</form>
<script>onload();</script>
</body>
</html>
The following code works:
<html>
<head>
<title>reCAPTCHA demo: Explicit render after an onload callback</title>
<script>
var onSubmit = function(token) {
console.log('success!');
};
var onloadCallback = function() {
widgetId1 = grecaptcha.render('recaptcha', {
'sitekey' : 'XXXXXXXXXXXXXXXXXX',
'callback' : onSubmit
});
};
</script>
</head>
<body>
<script src="/wp-content/themes/kc_water_care_services/js/pristine.min.js"></script>
<form action="?" method="POST" id="contactForm">
<div class="form-group">
<label for="name">Name (required)</label>
<input type="text" required data-pristine-required-message="Please enter your name"
id="name" name="name" />
</div><!--/.form-group-->
<div id="recaptcha" data-size="invisible"></div>
<input id="submit" type="submit" value="Submit">
</form>
<script src="https://www.google.com/recaptcha/api.js?onload=onloadCallback&render=explicit" async defer>
</script>
</body>
</html>
<script>
var form = document.getElementById("contactForm");
// create the pristine instance
var pristine = new Pristine(form);
form.addEventListener('submit', function (event) {
event.preventDefault();
// check if the form is valid
var valid = pristine.validate(); // returns true or false
if(valid == true){
grecaptcha.execute(widgetId1);
}
});
</script>
Turns out the id doesn't refer to the css ID, it refers to an ID created when you use the render function.

Send method in new Vue is not called when form is submitted

<!DOCTYPE html>
<head>
<meta charset=" UTF-8">
<title> Document</title>
</head>
<body id="chat">
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/1.5.0/socket.io.min.js"></script>
<script src="http://code.jquery.com/jquery-1.11.1.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.0.3/vue.min.js"></script>
<form v-on="submit: send">
<input v-model="message">
<button>Send</button>
</form>
<script>
var socket = io();
new Vue({
el: '#chat',
date: {
message: ''
},
methods: {
send: function(e)
{
e.preventDefault();
alert("a");
}
}
})
</script>
</body>
I want to call the send method defined in new Vue when the form is submitted ,
But when i submit the form, page is reloading.
I have created a Vue object and linked it to the chat element.
I guess e.preventDefault() is not working.
Interesting, I just helped somebody with a similar issue, the syntax for Vue.2.0 is v-on:submit="send" not v-on="submit: send". Vue already has a way stop the form submitting which is: v-on:submit.prevent so you don't need the e.preventDefault, you would get:
<form v-on:submit="send" v-on:submit.prevent>
or a shorter version:
<form v-on:submit.prevent="send">
There are a few more issues here, so I will go through them for you:
Firstly, you are never submitting the form. To submit a form you need a submit input, not a button:
<input type="submit" value="Send" />
However, from what I can see it's likely you don't even need a form, and can simply use a button with v-on:click:
<div>
<input v-model="message">
<button v-on:click="send">Send</button>
</div>
And then get what was submitted from the view model:
send: function()
{
alert(this.message);
}
You should also use the console (under developer tools in your browser) and log any output rather than alert (console.log(this.message)), because it will also sniff out any general errors with your code - for example I can see that you also have a typo (the same one I always make) it's data not date:
data: {
message: ''
},
Okay, what about this
<form #submit.prevent="send">
<input v-model="message">
<button>Send</button>
</form>
And then you can remove preventing default browser action from your send() method

angular-ui bootstrap typeahead limit is not working

I am new to angularjs. From this web site https://angular-ui.github.io/bootstrap/ I got typeahead directive for my angularjs project but my limit and filter are not working here is my code.
When I type "c" in the text field I want only 8 records to be displayed but instead all records are displayed.
plunker
http://plnkr.co/edit/RhwHmKwSxWBh3rp0u85O?p=preview
angular.module('ui.bootstrap.demo', ['ui.bootstrap']);
angular.module('ui.bootstrap.demo').controller('TypeaheadCtrl', function($scope, $http) {
$scope.getLocation = function(val) {
return $http.get('http://maps.googleapis.com/maps/api/geocode/json', {
params: {
address: val,
sensor: false
}
}).then(function(response){
return response.data.results.map(function(item){
return item.formatted_address;
});
});
};
});
<!doctype html>
<html ng-app="ui.bootstrap.demo">
<head>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.13/angular.js"></script>
<script src="//angular-ui.github.io/bootstrap/ui-bootstrap-tpls-0.13.0.js"></script>
<script src="example.js"></script>
<link href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<script type="text/ng-template" id="customTemplate.html">
<a>
<img ng-src="http://upload.wikimedia.org/wikipedia/commons/thumb/{{match.model.flag}}" width="16">
<span bind-html-unsafe="match.label | typeaheadHighlight:query"></span>
</a>
</script>
<div class='container-fluid' ng-controller="TypeaheadCtrl">
<h4>Asynchronous results</h4>
<pre>Model: {{asyncSelected | json}}</pre>
<input type="text" ng-model="asyncSelected" placeholder="Locations loaded via $http" typeahead="address for address in getLocation($viewValue) | filter:$viewValue |limitTo:8" typeahead-loading="loadingLocations" class="form-control">
<i ng-show="loadingLocations" class="glyphicon glyphicon-refresh"></i>
</div>
</body>
</html>
I know this is an old question, but I'll go ahead and answer it anyway for future reference:
This is a known behaviour when loading via $http as the limit would apply to the promise when calling your get method, which would result in it not applying to the actual result set by the time your promise resolves.
See issue #1740 in ui.bootstrap repository for more information on this.
The work around for this is either rolling your own filter function and return a promise from that filter instead of fetching the records directly or implement a limit parameter in the API and limit it server side.

Routing for Symfony2 TWIG templates with AJAX

I have been struggling with this for a couple days and have yet to find any real solutions online yet. I have a form that allows users to enter their email, then after they enter it fades out and is replaced by another form. I am using ajax to submit data from a form to a symfony2 controller, which stories it in the database and sends a response. However, the response ends up just sending me to a blank page with the response data displayed, instead keeping me on the same page and just fading the boxes as needed. I think my issue is with how I have the controller actions set up and the routing files.
EDIT
Well now the issue is that when I click on the submit button nothing happens. Nothing is sent to the controller, so nothing is being stored and no response is being given. What I changed was based on the answer by #PaulPro, appending the
<script> $('#emailForm').submit(submitForm); </script>
to the end of the html page. Thanks in advance for any help and insight!
The controller has 2 relevant actions, the one that renders the TWIG Template with the form, and the one that handles the ajax form submission and returns the response.
public function emailAction()
{
return $this->render('Bundle:email.html.twig');
}
public function submitEmailAction()
{
$em = $this->getDoctrine()-> getEntityManager();
$email = new Email();
$request = $this->getRequest();
$emailVar = $request->request->get('emailSignup');
$email -> setEmail($emailVar);
$em->persist($email);
$em->flush();
$return=array("responseCode"=>200);
$return = json_encode($return);
return new Response($return, 200, array('Content-Type'=>'application/json'));
}
This is the routing for those actions, most likely the culprit of it all:
Bundle_email:
pattern: /email
defaults: { _controller: Bundle:email }
requirements:
_method: GET
Bundle_submitEmail:
pattern: /submitEmail
defaults: { _controller: Bundle:submitEmail }
requirements:
_method: POST
And then here is the email.html.twig template and ajax script:
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<link href="{{asset('css/styles.css')}}" rel="stylesheet" type="text/css" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.min.js"></script>
<script type="text/javascript">
function submitForm(){
var emailForm = $(this);
var path = "{{path('Bundle_submitEmail')}}"
$.ajax ( {
type: 'POST',
url: $("#emailForm").attr("action"),
emailSignup: $("#emailId").val(),
success: function(data){
if(data.responseCode==200 ){
$('.email-signup-form').fadeOut();
$('.share-form').delay(500).fadeIn();
}
}
});
return false;
}</script>
</head>
<body>
<form id="emailForm" action="{{path('Bundle_submitEmail')}}" method="POST" class="email-signup-form">
<input type="email" placeholder="e-mail address" name="emailSignup" id="emailId" required="true"/>
<input type="submit" value="Go">
</form>
<form class="share-form">
</form>
<script> $('#emailForm').submit(submitForm); </script>
</body>
</html>
You don't ever call submitForm (the function that tells the browser to use AJAX rather than a full page load). Just add a script at the end of your body that looks like:
<script>
$('#emailForm').submit(submitForm);
</script>

Fire button click in AngularJS

I want to fire a button's click event when pressing ENTER inside a input and I find it quite difficult with AngularJS.
My view (simplified, updated):
<!doctype html>
<html lang="en" ng:app="test">
<head>
<meta charset="utf-8" />
<title>Test</title>
<link rel="stylesheet" href="css/app.css" />
</head>
<body ng-controller="TestController">
<button ng-click="onButton1Click()" class="btn1">Click Me</button>
<button ng-click="onButton2Click()" class="btn2">Don't click me</button>
<script src="lib/jquery/jquery.js"></script>
<script src="lib/angular/angular.js"></script>
<script src="js/testcontroller.js"></script>
</body>
</html>
My controller for this view:
'use strict';
angular.module('test', [])
.controller('TestController', ['$scope',
function($scope) {
$scope.onButton1Click = function() {
alert("Hello");
}
$scope.onButton2Click = function() {
$('.btn2').click();
}
}])
I simplified all the code to this. When I click on btn2 I get this error
$apply already in progress
No, I can't call $scope.onButton1Click() directly, I must simulate the btn1 click.
You mentioned
fire a button's click event when pressing ENTER inside a input
So if it is safe to assume that you can have a form I would prefer using ng-submit as shown below.
<form ng-submit="clickEventFunction()">
<input type="text"/>
<button type="submit">Click</button>
</form>
Note button type should be submit.
This took me a while to figure out (lots of fiddles).
<form id="nowsorting" ng-submit="getData(sc_user)">Now sorting the Soundcloud likes of <input type="text" ng-model="sc_user"><input type="submit" value="Sort"></form>
Make a form and use ng-submit to fire the event (likely a function).
Then create two inputs (one is "text" and the other "submit").
Then pushing enter should fire the ng-submit event/function.
I think, you just have to call your $scope.onButtonClick()
Please check this Plunker
$scope.onKeyPress = function($event) {
if ($event.keyCode == 13) {
$scope.onButtonClick();
}
};

Resources