Meteor - preventDefault not preventing default - javascript

I'm busy with David Turnbull's - Your first Meteor Application. Everything works up to the point where I try and add a new player to the list via a form. My problem is that preventDefault is not preventing the form from trying to submit and reloading the page. return false doesn't work either.
Any ideas why this will be happening?
Thanks
PlayersList = new Mongo.Collection('players');
if (Meteor.isClient) {
//Helpers
Template.leaderboard.helpers({
'player': function() {
return PlayersList.find({}, {sort: {score: -1, name: 1}});
},
'playerCount': function() {
return PlayersList.find().count();
},
'selectedClass': function() {
var playerId = this._id;
var selectedPlayer = Session.get('selectedPlayer');
if(playerId == selectedPlayer) {
return 'selected'
}
},
'showSelectedPlayer': function() {
var selectedPlayer = Session.get('selectedPlayer');
return PlayersList.findOne(selectedPlayer);
}
});
//Events
Template.leaderboard.events({
'click .player': function() {
var playerId = this._id;
Session.set('selectedPlayer', playerId);
},
'click .increment': function() {
var selectedPlayer = Session.get('selectedPlayer');
var increaseBy = document.getElementById('increase-by').value;
var isNumber = /^\d+$/.test(increaseBy);
if(increaseBy != '' && isNumber) {
PlayersList.update(selectedPlayer, {$inc: {score: +increaseBy}});
}
},
'click .decrement': function() {
var selectedPlayer = Session.get('selectedPlayer');
var decreaseBy = document.getElementById('decrease-by').value;
PlayersList.update(selectedPlayer, {$inc: {score: -decreaseBy}});
},
'submit #new-player': function(event) {
event.preventDefault();
var playerNameVar = event.target.playerName.value;
if(playerNameVar != '') {
PlayersList.insert({
name: playerNameVar,
score:0
});
}
}
});
}
Template
<template name="addPlayerForm">
<div id="add-player" class="reveal-modal" data-reveal>
<a class="close-reveal-modal">×</a>
<h2>Add a player</h2>
<p class="lead">Add another player to the leaderboard</p>
<div class="row">
<div class="small-8 column small-centered">
<form id="new-player">
<div class="row collapse">
<div class="small-8 column">
<input type="text" placeholder="Player name" name="playerName">
</div>
<div class="small-4 column">
<input type="submit" class="button postfix" value="add player">
</div>
</div>
</form>
</div>
</div>
</div>
</template>

I've never read the book, and I don't know what your template looks like, but the problem is likely due to a selector issue.
Maybe try assigning an id to your form and mapping the submit event to that id:
// html file
<Template name="leaderboard">
<form id="new-player">
<input type="text" name="playerName">
<input type="submit" value="Submit">
</form>
</Template>
// js file
Template.leaderboard.events({
'submit #new-player': function(event) {
event.preventDefault();
...
}
});
Edit
Maybe try changing Template.leaderboard.events to Template.addPlayerForm.events.

Ok, I made the same mistake as the poster and I am putting the correct code here:
In html file:
<template name="addPlayerForm">
<form>
<input type="text" name="playerName">
<input type="submit" value="Add Player">
</form>
</template>
In js file:
Template.addPlayerForm.events({
'submit form': function(event){
event.preventDefault();
console.log("Form submitted");
console.log(event.type);
}
});

Related

Hiding element in IE causing form submit

I am getting some strange behaviour within IE which I was hoping someone might be able to explain. I have a simple form with an address lookup input
<form action="http://localhost:8000/processForm" method="post">
<label for="input_1" class="form-control-label col-xs-12">
Postcode
</label>
<div class="col-xs-12">
<div class="input-group">
<input type="text" name="questions[1]" autocomplete="off" id="input_1" class="form-control address" value="" >
<a class="btn btn-xs input-group-addon address-button" id="input_address_addon" role="button" tabindex="0">
<img src="http://localhost:8000/images/glyphicons-243-map-marker.png">
Search
</a>
</div>
<div class="col-xs-12 col-sm-8 col-sm-offset-4 col-md-7">
<select class="form-control selectpicker addSelect" id="input_address_select" style="display: none;">
<option value="">Enter above</option>
</select>
</div>
</div>
<button type="submit" class="btn submit btn-navigation">
Continue
</button>
</form>
The address is entered into the input, then the search button is clicked. This makes a call to an API to return addresses and populate the a select input with them. This all works fine in all browsers, but noticed something strange with IE. This is the Javascript that handles the API call and populating of the select.
!function ($, window) {
$(function () {
init();
});
var getAddresses = function (postcode, callback) {
var $xhr = $.getJSON('/lookupPostcode/' + postcode);
$xhr.done(function (data) {
callback(data);
});
$xhr.error(function () {
callback([]);
})
};
var init = function () {
$("input.address").each(function () {
var $input = $(this);
var $icon = $input.next('.address-button');
var $select = $input.parents('.row').eq(0).find("select");
$select.css("display", "none");
var onKeyUp = function (e) {
if (e.keyCode === 13) {
e.preventDefault();
e.stopPropagation();
$icon.trigger("click");
}
};
var onKeyDown = function(e) {
if (e.keyCode === 13) {
e.preventDefault();
e.stopPropagation();
}
};
$input.on("keyup", onKeyUp);
$input.on("keydown", onKeyDown);
$icon.on("keyup", onKeyUp);
$icon.on("keydown", onKeyDown);
$select.on("keyup", onKeyUp);
$icon.on("click", function () {
getAddresses($input.val(), function (addresses) {
//populate select options with addresses
});
});
$select.on('change', function (event) {
var ua = window.navigator.userAgent;
var is_ie = /MSIE|Trident/.test(ua);
if ( !is_ie ) {
$select.css("display", "none");
}
/*$select.css("display", "none");*/
});
});
};
}(jQuery, window);
So when an address is selected from the select input, I hide the select input. On IE, this hiding of this element seems to make the form submit. You can see above that I have added some code to check that it is not IE and only hide on these devices, and keeping the select in place on IE works fine. Also, if I put an alert at the top of the change event, this also seems to stop the form submitting in IE.
So I was wondering what may be causing this to submit in IE if I hide the select? I have read that IE does not like buttons to be used as form submits, but not sure if this is the issue?
Is there any way to get the select hiding in IE?
Thanks
So I was wondering what may be causing this to submit in IE if I hide
the select? I have read that IE does not like buttons to be used as
form submits, but not sure if this is the issue?
I can't reproduce your problem, everything works well on my side (IE 11.1.17340.0 version).
Please try to use the following code: (based on your code, please note the part of code with comment)
<head runat="server">
<title></title>
<script src="Scripts/jquery-1.10.2.min.js"></script>
<script type="text/javascript">
!function ($, window) {
$(function () {
init();
});
var getAddresses = function (postcode, callback) {
//var $xhr = $.getJSON('/lookupPostcode/' + postcode);
//$xhr.done(function (data) {
// callback(data);
//});
//$xhr.error(function () {
// callback([]);
//})
//using the following array to populate the select.
var datalist = [{ "ID": "1", "ParentID": "0", "Name": "Parent1" }, { "ID": "2", "ParentID": "0", "Name": "Parent2" },
{ "ID": "3", "ParentID": "1", "Name": "Child 1.1" }, { "ID": "4", "ParentID": "1", "Name": "Child 1.2" },
{ "ID": "5", "ParentID": "3", "Name": "SubChild 1.1.1" }, { "ID": "6", "ParentID": "2", "Name": "Child 2.1" }];
callback(datalist);
};
var init = function () {
$("input.address").each(function () {
var $input = $(this);
var $icon = $input.next('.address-button');
//you are using the .row class to find the select control, but from your form, I can't find this class.
var $select = $input.parents('.row').eq(0).find("select");
//debugger;
$select.css("display", "none");
var onKeyUp = function (e) {
if (e.keyCode === 13) {
e.preventDefault();
e.stopPropagation();
$icon.trigger("click");
}
};
var onKeyDown = function (e) {
if (e.keyCode === 13) {
e.preventDefault();
e.stopPropagation();
}
};
$input.on("keyup", onKeyUp);
$input.on("keydown", onKeyDown);
$icon.on("keyup", onKeyUp);
$icon.on("keydown", onKeyDown);
$select.on("keyup", onKeyUp);
$icon.on("click", function () {
$select.empty();
$select.append("<option value=''>Enter above</option>");
getAddresses($input.val(), function (addresses) {
//populate select options with addresses
$.each(addresses, function (index, item) {
//debugger;
$select.append("<option value='" + item.ID + "'>" + item.Name + "</option>");
});
$select.css("display", "block");
});
});
$select.on('change', function (event) {
var ua = window.navigator.userAgent;
var is_ie = /MSIE|Trident/.test(ua);
//get the selected text and populate the input text.
$input.val($(this).find("option:selected").text());
//hide the select control
if (!is_ie) {
$select.css("display", "none");
}
$select.css("display", "none");
});
});
};
}(jQuery, window);
</script>
</head>
<body>
<form action="http://localhost:8000/processForm" method="post">
<label for="input_1" class="form-control-label col-xs-12">
Postcode
</label>
<div class="col-xs-12 row">
<div class="input-group">
<input type="text" name="questions[1]" autocomplete="off" id="input_1" class="form-control address" value="" />
<a class="btn btn-xs input-group-addon address-button" id="input_address_addon" role="button" tabindex="0">
<img src="http://i.imgur.com/H9FIags.jpg" style="height:10px;width:10px" />
Search
</a>
</div>
<div class="col-xs-12 col-sm-8 col-sm-offset-4 col-md-7">
<select class="form-control selectpicker addSelect" id="input_address_select" >
<option value="">Enter above</option>
</select>
</div>
</div>
<button type="submit" class="btn submit btn-navigation">
Continue
</button>
</form>
</body>
The output as below:
The reason why your form submits is the fact that you have a button of type "submit" in your form.
<button type="submit"...>
Whenever you press enter, this will cause your form to submit.
You need to change your submit button to another type like "button" and add a Javascript event handler to it (for example onClick="submit()").
<button type="button" class="btn submit btn-navigation" onClick="submit(this.form)">
Continue
</button>
function submit(form){
form.submit();
}

form does not submit when using ng-click

I have a simple form which need to submit when click button and hide stuff with ng-click, it does submit the form when I don't add the ng-click for the hide stuff purpose, when I add the ng-click the form don't submit:
the form head :
<form class="form" name="form" ng-submit="edit(form)" novalidate ng-show="editorEnabledView">
the button :
<button analytics-on analytics-event="Bouton Terminer" analytics-category="Profil" ng-click="disableEdditing()" class="btn btn-lg btn-primary" type="submit">{{ step == 2 ? 'Terminer' : 'Enregistrer' }}</button>
CTRL
$scope.editorEnabledView = false;
$scope.showEdditing = function () {
$scope.editorEnabledView = true;
console.log("YES TRUE");
}
$scope.disableEdditing = function () {
$scope.editorEnabledView = false;
}
my edit function :
$scope.edit = function (form) {
if (!form.$valid) return;
$scope.errors = {};
if (!$scope.address.input) $scope.errors.address = 'Votre adresse de travail est obligatoire.';
var data = {
gender: $scope.user.gender,
name: {
first: $scope.user.name.first,
last: $scope.user.name.last
},
phone: $scope.user.phone,
job: {
name: $scope.user.job.name,
status: $scope.user.job.status
},
about: $scope.user.about,
interests: $scope.user.interests
};
getAddress(function (response) {
data.address = {
full: response.formatted_address,
city: getCity(response.address_components),
latitude: response.geometry.location.lat(),
longitude: response.geometry.location.lng(),
timestamp: new Date()
};
User.update(data, function (user) {
submit = true;
Auth.update(user);
if ($scope.step == 1) return $scope.step++;
$location.path($scope.step == 2 ? '/' : '/users/view/' + user._id);
}, function (err) {
Auth.update(originalUser);
$scope.user = originalUser;
angular.forEach(err.data.errors, function (error, field) {
$scope.errors[field] = error.message;
});
});
});
//$scope.editorEnabledView = false;
};
I discovered that when go to another page and come back to the user profile I see that the form get submitted !! but I want to see it after the submit
I had to change my answer cause now its clear that all you want to do is to hide your form after submit. This can be done with the use of form.$submitted and ng-hide
<div ng-controller="MyCtrl">
<form class="form" name="form" ng-submit="edit(form)" ng-hide="form.$submitted" ng-show="!form.$submitted" novalidate >
</div>
<button analytics-on analytics-event="Bouton Terminer" analytics-category="Profil" class="btn btn-lg btn-primary" type="submit">{{ step == 2 ? 'Terminer' : 'Enregistrer' }}</button>
I did a snippet and everything seems to be working... I think you are doing something wrong. Maybe you are missing the ng-submit in the form tag. See my snippet and change your code.
var $scope = {};
var myApp = angular.module('myApp', []);
myApp.controller('ngSubmitCtrl', ['$scope', function($scope){
$scope.editorEnabledView = true;
$scope.showEdditing = function () {
$scope.editorEnabledView = true;
alert("showEdditing");
}
$scope.disableEdditing = function () {
$scope.editorEnabledView = false;
alert("disableEdditing");
}
$scope.edit = function (form) {
alert("submitForm");
}
}]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app='myApp' ng-controller="ngSubmitCtrl">
<form class="form" name="form" ng-submit="edit(form)" novalidate ng-show="editorEnabledView">
<button
analytics-on analytics-event="Bouton Terminer"
analytics-category="Profil"
ng-click="disableEdditing()"
class="btn btn-lg btn-primary"
type="submit">{{ step == 2 ? 'Terminer' : 'Enregistrer' }}
</button>
</form>
</div>
Why do you send form inside edit call?
<form class="form" name="form" ng-submit="edit()">
<input type="text" ng-model="formData.name">
</form>
in your controller
$scope.edit = function() {
console.log($scope.formData)
}
Or if you want to call edit function with parameter means
<form class="form" name="form" ng-submit="edit(form)">
<input type="text" ng-model="form.name">
</form>
in your controller
$scope.edit = function(data) {
console.log(data)
}
This should work. But we don't get your problem. If you show full code, we will help.

Javascript init function breaks because of this keyword?

I'm having issues writing my JavaScript/Jquery correctly because I'm a newbie. I have a couple of functions that are breaking each other because of the this keyword. All of the functions that are breaking are listed below and the last one is what causes me to know that it is the this keyword:
// Functions that break
var gp;
gp = function() {
var autocomplete, input, types;
input = document.getElementById('loc-input');
types = document.getElementById('type-selector');
autocomplete = new google.maps.places.Autocomplete(input);
};
google.maps.event.addDomListener(window, 'load', gp);
$('a[href="' + this.location.pathname + '"]').parent('.navbar-nav li').addClass('active');
$('ul.nav li.dropdown, .dropdown-hover').hover((function() {
$(this).find('.dropdown-menu').stop(true, true).delay(50).fadeIn();
}), function() {
$(this).find('.dropdown-menu').stop(true, true).delay(50).fadeOut();
});
$('.form-control').mousedown(function() {
if (!$(this).is(':focus')) {
return;
}
$(this).blur().focus();
});
$('#new_item').dropzone({
acceptedFiles: '.jpeg, .jpg, .png',
// Area that causes functions to break
init: function() {
var myDropzone;
myDropzone = this;
this.element.querySelector('button[type=submit]').addEventListener('click', function(e) {
e.preventDefault();
e.stopPropagation();
myDropzone.processQueue();
});
this.on('sendingmultiple', function() {});
this.on('successmultiple', function(files, response) {});
this.on('errormultiple', function(files, response) {});
}
});
This area right here (inner function) if commented out makes all the JavaScript work again but if used, all is lost:
init: function() {
var myDropzone;
myDropzone = this;
this.element.querySelector('button[type=submit]').addEventListener('click', function(e) {
e.preventDefault();
e.stopPropagation();
myDropzone.processQueue();
});
this.on('sendingmultiple', function() {});
this.on('successmultiple', function(files, response) {});
this.on('errormultiple', function(files, response) {});
}
So I'm trying to figure how I can get all of these functions to work as they should or without the use of the this keyword and still self-reference?
Edit
So with the Chrome extension: Javascript Errors Notifier. I was able to see the error saying:
TypeError: Cannot read property 'addEventListener' of null
I made a gist of the returned JavaScript here:
https://gist.github.com/justintech/d6d5bdb8468b79f60663
Edit 2 - The form
<div class="row">
<div class="col-lg-8 col-lg-offset-2">
<form data-validate="true" class="form-horizontal form" id="new_item" enctype="multipart/form-data" action="/items" accept-charset="UTF-8" method="post"><input name="utf8" type="hidden" value="✓"><input type="hidden" name="authenticity_token" value="/pbJ8IQK+ybIrjXFD7t2MIWzzFKsvmF7DA9oKSnNxouMk6i+jLNsboDZELHM5+w2qEnE0qzBEXyNFGl7HB85kQ==">
<fieldset>
</div>
<main id="image-preview" class="dz-clickable">
</main>
<div class="submit-section">
<div class="col-lg-12 col-md-12">
<input type="submit" name="commit" value="Done" id="item-submit" class="btn btn-primary btn-lg btn-block">
</div>
</div>
</fieldset>
</form>
</div>
</div>
Using this
document.querySelector('#item-submit')
instead of this
this.element.querySelector('button[type=submit]')
will fix the problem you are seeing. Will that work for you?

Updating value when overriding enter press

I have page when I have input and a button.
<div>
<div class="input-group">
<span class="input-group-addon">Enter test</span>
<input type="Text" class="form-control" data-bind="value:Test, event: { keypress: searchKeyboardCmd}" required />
</div>
</div>
<button data-bind=' event:{click:foo}' class="btn btn-default">Submit</button>
and my code:
var ViewModel = function () {
var self = this;
self.Test = ko.observable();
self.data = ko.observableArray([]);
self.DeviceId = ko.observable();
self.number = ko.observable(1);
self.MeUser = ko.observable(true);
self.searchKeyboardCmd = function (data, event) {
if (event.keyCode == 13)
alert("Znalazlem enter " + ko.toJSON(self));
return true;
};
self.foo = function () {
alert("foo");
}
};
ko.applyBindings(new ViewModel());
});
And I have problems with my code. I catch enter with this code:
self.searchKeyboardCmd = function (data, event) {
if (event.keyCode == 13)
alert("Znalazlem enter " + ko.toJSON(self));
return true;
};
It's catches perfectly but binded object is updated after calling alert. So in the first enter I null in value Test. After second enter I have first value and so on. Can anyone suggest me how to modify this code?
The problem is that the event is executed before the blur event (which is when the value is updated. You can make sure the update gets updated after every keystroke by adding valueupdate: 'afterkeydown' to the input:
<div>
<div class="input-group">
<span class="input-group-addon">Enter test</span>
<input type="Text" class="form-control"
data-bind="valueUpdate: 'afterkeydown', value:Test, event: { keypress: searchKeyboardCmd}" required />
</div>
</div>
<button data-bind=' event:{click:foo}' class="btn btn-default">Submit</button>

Backbone js and elements

I am currently working on a data input form that will take as in input some time parameters. As a result, I desire to use a jquery timepicker in these fields, within the itemview. This is my first time attempting to interact with the internal elements of an itemview and assistance would be greatly appreciated.
This is what i have attempted so far.
<div class="grid_15 top-m">
<div class="grid_16"><h3>Class Sessions</h3> <i>(eg. Period 1, Period 2 etc)</i></div>
<div class="grid_16">
<div id="sessionlist"></div>
<br/><br/>
</div>
<div>
<a id="addses" class="top-m" href="#">Add</a>
<a id="removeses" class="top-m" href="#" style="display:none" >Remove</a>
</div>
</div>
The add and remove buttons remove and add itemviews as desired.
<script type="text/html" id="SFTemplate">
<div class="editor-label">
<label for="Sessions[{{ count }}].Name">Session Name</label>
</div>
<div class="editor-field">
<input type="textbox" id="Sessions[{{ count }}].Name" name="Sessions[{{ count }}].Name"/>
</div>
<div class="editor-label">
<label for="Sessions[{{ count }}].StatTime">Session Start Time</label>
</div>
<div class="editor-field">
<input type="textbox" id="Sessions[{{ count }}].StartTime" name="Sessions[{{ count }}].StartTime"/>
</div>
<div class="editor-label">
<label for="Sessions[{{ count }}].EndTime">Session End Time</label>
</div>
<div class="editor-field">
<input type="textbox" id="Sessions[{{ count }}].EndTime" name="Sessions[{{ count }}].EndTime"/>
</div>
That is the template for the itemview
<script>
window.CreateSession = (function () {
var CreateSession = {};
var ses = new Array();
//The next of kin item list view
SessionItemView = Backbone.View.extend({
tagName: 'div',
initialize: function () {
//bindall
_.bindAll(this, 'render');
this.template = _.template($('#SFTemplate').html());
this.render();
},
render: function () {
$(this.el).html(this.template({
count: ses.length
})).fadeIn();
return this;
},
remove: function () {
$(this.el).fadeOut('fast', function () {
$(this).remove();
});
return false;
},
**events: {
"click input[type=textbox]": "placetimepicker"
},
placetimepicker: function (e) {
e.el.timepicker({ ampm: true,
hourMin: 8,
hourMax: 16
});**
}
});
function sesUpdated() {
if (ses.length > 0) {
$('#removeses').fadeIn();
}
else {
$('#removeses').fadeOut();
}
}
CreateSession.Init = function () {
$('#addses').click(function () {
var item = new SessionItemView();
ses.push(item);
$('#sessionlist').append($(item.el).fadeIn('fast'));
sesUpdated();
return false;
});
$('#removeses').click(function () {
if (ses.length > 0) {
ses.pop().remove();
}
sesUpdated();
return false;
});
};
return CreateSession;
})(this, this.document);
$(function () {
CreateSession.Init();
});
After more research and trial and error, I found where my code was lacking.
**events: {
"click .timepicker": "placetimepicker"
},
placetimepicker: function () {
this.$(".timepicker").timepicker({ ampm: true,
hourMin: 8,
hourMax: 16
});**
}
});
I put a class timepicker on the textboxes and using the 'this' keyword I could append the jquery code unto the entire itemview.
Backbone is cool. :-D
It's difficult to determine your question. What I think your asking is why the timepicker is not initializing for your inputs. Try wrapping your event element in jquery $(e.el) since your timepicker is a jquery plugin:
placetimepicker: function (e) {
$(e.el).timepicker({ ampm: true,
hourMin: 8,
hourMax: 16
});

Categories

Resources