jquery live not firing on first click on a checkbox - asp.net-mvc-2

I have a strange problem. This code works fine in chrome and firefox, but in IE 8 the live event will not fire the first time I uncheck a box. If I check it and then uncheck again it works every time after that.
My serverside code in the view
<%: Html.CheckBox("select-invoice-" + invoice.InvoiceNumber,
true,
new { title = "choose to not pay anything on this invoice by unchecking this box" }) %>
renders to this
<input checked="checked" id="select-invoice-TST-1001"
name="select-invoice-TST-1001"
title="choose to not pay anything on this invoice by unchecking this box"
type="checkbox" value="true" />
Here is my javascript live event wireup, simplified
$(function () {
$("[id^='select-invoice-']").live('change', function () {
var invoiceId = $(this).attr('id').substr('select-invoice-'.length);
ComputeTotalPayment();
if ($(this).is(':checked')) {
//save invoice data
} else {
//remove invoice data
}
});
});
There are no errors in the javascript on any browser. If I switch IE to compatibility mode the live event never works. Other live events for clicks on links work just fine.

The change event doesn't fire correctly in IE until the checkbox loses focus.
Bug: http://webbugtrack.blogspot.com/2007/11/bug-193-onchange-does-not-fire-properly.html
You'll need to map to the "click" event instead.

I have found that change causes some problems in IE. Try using the click event instead. This appears to fix the problem.

I had a similar problem and solved it by calling .change() once on page load.
$(function () {
$("[id^='select-invoice-']").live('change', function () {
var invoiceId = $(this).attr('id').substr('select-invoice-'.length);
ComputeTotalPayment();
if ($(this).is(':checked')) {
//save invoice data
} else {
//remove invoice data
}
}).change();
});

Related

Leaflet - How to add click event to button inside marker pop up in ionic app?

I am trying to add a click listener to a button in a leaftlet popup in my ionic app.
Here I am creating the map & displaying markers, also the method I want called when the header tag is clicked is also below:
makeCapitalMarkers(map: L.map): void {
let eventHandlerAssigned = false;
this.http.get(this.capitals).subscribe((res: any) => {
for (const c of res.features) {
const lat = c.geometry.coordinates[0];
const lon = c.geometry.coordinates[1];
let marker = L.marker([lon, lat]).bindPopup(`
<h4 class="link">Click me!</h4>
`);
marker.addTo(map);
}
});
map.on('popupopen', function () {
console.log('Popup Open')
if (!eventHandlerAssigned && document.querySelector('.link')) {
console.log('Inside if')
const link = document.querySelector('.link')
link.addEventListener('click', this.buttonClicked())
eventHandlerAssigned = true
}
})
}
buttonClicked(event) {
console.log('EXECUTED');
}
When I click this header, Popup Open & Inside if are printed in the console, so I know I'm getting inside the If statement, but for some reason the buttonClicked() function isn't being executed.
Can someone please tell me why this is the current behaviour?
I just ran into this issue like 2 hours ago. I'm not familiar with ionic, but hopefully this will help.
Create a variable that keeps track of whether or not the content of your popup has an event handler attached to it already. Then you can add an event listener to the map to listen for a popup to open with map.on('popupopen', function(){}). When that happens, the DOM content in the popup is rendered and available to grab with a querySelector or getElementById. So you can target that, and add an event listener to it. You'll have to also create an event for map.on('popupclose', () => {}), and inside that, remove the event listener from the dom node that you had attached it to.
You'd need to do this for every unique popup you create whose content you want to add an event listener to. But perhaps you can build a function that will do that for you. Here's an example:
const someMarker = L.marker(map.getCenter()).bindPopup(`
<h4 class="norwayLink">To Norway!</h4>
`)
someMarker.addTo(map)
function flyToNorway(){
map.flyTo([
47.57652571374621,
-27.333984375
],3,{animate: true, duration: 5})
someMarker.closePopup()
}
let eventHandlerAssigned = false
map.on('popupopen', function(){
if (!eventHandlerAssigned && document.querySelector('.norwayLink')){
const link = document.querySelector('.norwayLink')
link.addEventListener('click', flyToNorway)
eventHandlerAssigned = true
}
})
map.on('popupclose', function(){
document.querySelector('.norwayLink').removeEventListener('click', flyToNorway)
eventHandlerAssigned = false
})
This is how I targeted the popup content and added a link to it in the demo for my plugin.
So yes you can't do (click) event binding by just adding static HTML. One way to achieve what you want can be by adding listeners after this new dom element is added, see pseudo-code below:
makeCapitalMarkers(map: L.map): void {
marker.bindPopup(this.popUpService.makeCapitalPopup(c));
marker.addTo(map);
addListener();
}
makeCapitalPopup(data: any): string {
return `` +
`<div>Name: John</div>` +
`<div>Address: 5 ....</div>` +
`<br/><button id="myButton" type="button" class="btn btn-primary" >Click me!</button>`
}
addListener() {
document.getElementById('myButton').addEventListener('click', onClickMethod
}
Ideally with Angular, we should not directly be working with DOM, so if this approach above works you can refactor adding event listener via Renderer.
Also I am not familiar with Leaflet library - but for the above approach to work you need to account for any async methods (if any), so that you were calling getElementById only after such DOM element was successfully added to the DOM.

Prevent closing browser tab when form is dirty in Angular 2

How to prevent closing browser tab when form is dirty in Angular 2?
My html body contains a component:
<body>
<my-app>Loading, please wait...</my-app>
</body>
which contains a router navigation and a router outlet:
<nav>
(...)
</nav>
<router-outlet></router-outlet>
and when the router navigates to the edit page, I have some form there:
<form #myForm="ngForm">
<button pButton type="text" label="Save" (click)="onSave()" [disabled]="!myForm.valid || myForm.pristine"></button>
</form>
Now, if the form is not 'pristine', I want to ask for confirmation when the user tries to close the browser tab:
window.onbeforeunload = function() {
if (form.dirty) {
return "You have unsaved data changes. Are you sure to close the page?"
}
}
How can I access the dirty state of Angular form in canonical way from there? I could register an event to field change on each field and set the global dirty flag, but I'd have to put that code on every from and by every navigation and then maintain that code so that the message stays consistent. Is there any other way to check out if there's an angular form on the page, which is in dirty state?
Perhaps
#HostListener('window:beforeunload', ['$event'])
handleBeforeUnload(event) {
if (connected) {
return "You have unsaved data changes. Are you sure to close the page?"
}
}
Add a Hostlistener decorator. If there are unsaved changes on the form confirm dialog appears.
#HostListener('window:beforeunload', ['$event'])
handleBeforeUnload(event: Event) {
event.returnValue = false;
}
This works. Implement the hasUnsavedData() function accordingly.
hasUnsavedData(){
return this.myForm.dirty;
}
#HostListener('window:beforeunload', ['$event'])
handleBeforeUnload($event: any) {
if (this.hasUnsavedData()) {
$event.returnValue = true;
}
}
Simply you can use Jquery to get state of ng-form.
#HostListener('window:beforeunload', ['$event'])
beforeUnloadHandler(event) {
if($('form').hasClass('ng-touched')) { //You can check with ng-dirty based on your requirements.
let confirmMessage = 'You have unsaved data changes. Are you sure to close the page?'
event.returnValue = confirmMessage;
return confirmMessage;
}
}
In my case am just showing warning dialog if that the form has been touched.
Try this directive https://github.com/extremeprog-com/ng-prevent-navigation.
So it should be simple
<div ng-prevent-navigation="vm.pageShouldBeReloaded"
ng-prevent-navigation-text="Payment form has unsaved changes.
If you leave the page now you will lose those changes."
></div>

AngularJS and Tab Order (Disabled Buttons)

I have a form, and I'm navigating only with TAB. Tab order should be input > select > button, but because of the ng-disable on the SUBMIT, on certain browsers the TAB out of the select will kick you somewhere else.
HTML
<div ng-app="myApp">
<div ng-controller="FirstCtrl">
<form name="myForm" ng-submit="submit()" novalidate>
First Name: <input type="text" ng-model="Data.FirstName" required><br>
Last Name: <select ng-model="Data.LastName" required>
<option value="Bigglesworth">Bigglesworth</option>
<option value="Burgermeister">Burgermeister</option>
</select><br>
<input type="submit" value="Submit" ng-disabled="myForm.$invalid" />
</form>
</div>
</div>
JS
var myApp = angular.module('myApp', []);
myApp.factory('Data', function(){
return {
FirstName: '',
LastName: ''
};
});
myApp.controller('FirstCtrl', function( $scope, Data ){
$scope.Data = Data;
$scope.submit = function() {
console.log('you just submitted, foolio');
}
});
JsFiddle here.
On Mac FF the final tab kicks you to the address bar before enabling the submit button. Mac Chrome works as you'd expect, focusing on the submit button after final tab. I know Windows is janky, but don't have exact specs to post.
Thoughts? How can I do this in a fool-proof fashion?
EDIT
I've selected #David B.'s answer as it's the best Angular solution. I ended up using a somewhat hidden element right after the the submit button so the focus would stay in the same general area. Lame and hacky, I know, but for a tight deadline it worked.
<h3><button class="fakebtn_hack">Confirmation</button></h3>
<style>.fakebtn_hack {background:none; border:none; color: #FF6319; cursor: default; font-size: 1em; padding: 0;}</style>
This happens because Firefox doesn't send a change event on key-driven changes of the select. Angular doesn't see the change until the tab is hit, so the submit button isn't enabled until after the tab has been processed by the browser (and focus sent to some other element, e.g., the address bar). The W3C standard suggests not sending the event until the control loses focus, although Chrome sends one for any change and Firefox does if the change was mouse-driven.
See the angularjs issue tracker for more: https://github.com/angular/angular.js/issues/4216
As suggested in the issue tracker, solve it by manually issuing the change event via the following select directive (http://jsfiddle.net/j5ZzE/):
myApp.directive("select", function () {
return {
restrict: "E",
require: "?ngModel",
scope: false,
link: function (scope, element, attrs, ngModel) {
if (!ngModel) {
return;
}
element.bind("keyup", function () {
element.trigger("change");
})
}
}
})
You'll need JQuery loaded before AngularJS to have the trigger function available on the element object.
Manually include an empty option (<option value=""></option>) in your select or the first option will be auto-selected when the control receives focus.
Unlike the default behavior, this empty option will not disappear after selecting a real option. I suppose you could remove the empty option by declaring all the options via ng-options or ng-repeat and then removing the empty one from the bound scope once a real option has been selected, but I've never tried it.

jQuery datepicker not opening up on focus

Heres my scenario: I have an index page with 2 radio buttons on it and a span area for results. When one of the radio buttons are clicked, the span fills up with an ajax generated page that has an input box as so :
<input size='25' class='datepicker' value='Click to enter deposit date' READONLY type='text' id='depositDate' name='depositDate'>
At the bottom of this page there is an 'Add Record' button which fires off javascript validation. The validation is so:
var inpDepDate = $.trim($("#depositDate").val());
if(inpPayDate=='Click to enter pay date') // Validate pay date
{
alert('Invalid pay date; re-enter');
document.getElementById('payDate').focus();
document.getElementById('payDate').select();
return false;
}
Also in my javascript file is :
$(function(){
$( "#depositDate" ).live('focus', function() {
$(this).datepicker({
changeMonth: true,
changeYear: true,
minDate: "+1D",
showOtherMonths: true,
selectOtherMonths: true}).focus();
});
});
The problem is when the validation fails, the text does get highlighted and selected but it does not open automatically.
Ive tried a number of things, actually a ton of things from this site, and no luck. And it seems to never recognize the live event. But if I click on the text box after its failed the validation (and the text is highlighted), the calendar opens just fine. Im fairly new at jQuery and ui.
You don't need to reinstantiate the datepicker if you've already called it on #depositDate in the past. (Or on payDate)
Try this:
if(inpPayDate=='Click to enter pay date') // Validate pay date
{
alert('Invalid pay date; re-enter');
$("#payDate").datepicker("show");
return false;
}

jQuery Stop .blur() event when clicking "submit" button

I am building a small landing page with a simple demo e-mail signup form. I want to have the form field open up when focused, and then shrink back down on blur.
However the problem I'm facing is when you click the submit button this instigates the blur function, hiding the button and shrinking the form. I need to find a way to stop the .blur() method only when the user is clicking to focus on the submit button. Is there any good workaround for this?
Would appreciate any help I can get!
I know this question is old but the simplest way to do it would be to check event.relatedTarget. The first part of the if statement is to prevent throwing an error if relatedTarget is null (the IF will short circuit because null is equivalent to false and the browser knows that it doesn't have to check the second condition if the first condition is false in an && statement).
So:
if(event.relatedTarget && event.relatedTarget.type!="submit"){
//do your animation
}
It isn't the prettiest solution, but it does work. Try this:
$("#submitbtn").mousedown(function() {
mousedownHappened = true;
});
$("#email").blur(function() {
if (mousedownHappened) // cancel the blur event
{
mousedownHappened = false;
}
else // blur event is okay
{
$("#email").animate({
opacity: 0.75,
width: '-=240px'
}, 500, function() {
});
// hide submit button
$("#submitbtn").fadeOut(400);
}
});​
DEMO HERE
Try this inside .blur handler:
if ($(':focus').is('#submitbtn')) { return false; }
why not rely on submit event instead of click? http://jsbin.com/ehujup/5/edit
just couple changes into the html and js
wrap inputs into the form and add required for email as it obviously suppose to be
<form id="form">
<div id="signup">
<input type="email" name="email" id="email" placeholder="me#email.com" tabindex="1" required="required">
<input type="submit" name="submit" id="submitbtn" value="Signup" class="submit-btn" tabindex="2">
</div>
</form>
in js, remove handler which listen #submitbtn
$("#submitbtn").on("click", function(e){
e.stopImmediatePropagation();
$("#signup").fadeOut(220);
});
and use instead submit form listerer
$("#form").on("submit", function(e){
$("#signup").fadeOut(220);
return false;
});
you may use $.ajax() to make it even better.
Doing this you gain point in terms of validation and the native browser's HTML5 validator will make check email format where it is supported.