angular-ui: datepicker seems to hang angularjs when showing button - javascript

I have this piece of html code in my application (the ng-app and ng-controller values are defined before):
<div>
<label for="projectSearchDateFrom"><%= Res("Projects.Search.From")%></label>
<input id="projectSearchDateFrom" type="text" ng-model="startDate" ui-date="dateOptions"/>
<img ng-show="hasStartDate()" ng-click="clearStartDate()" src="/_Layouts/ClientPortal/Images/layout/TA/delete-small.png" alt="<%= Res("ToolbarDialog.Clear")%> <%= Res("Projects.Search.From")%>" title="<%= Res("ToolbarDialog.Clear")%>" />
</div>
My AngularJS controller looks like this:
function ProjectSearchCtrl($scope) {
$scope.startDate = '';
$scope.hasStartDate = function () {
return $scope.startDate != '';
};
$scope.clearStartDate = function () {
$scope.startDate = '';
};
$scope.dateOptions = {
dateFormat: "yy-mm-dd",
showOn: "focus"
};
}
This works perfectly: I have a datepicker set up correctly thanks to AngularUI, the AngularJS binding works...
But if I change the showOn value to "button" or "both" (the two possible options which will actually show the datepicker button), everything after the input (containing the ui-date attribute) stops working: ng-show, ng-click... The controller doesn't even get called.
Versions (all is up-to-date):
jQuery 1.7.2
angularJS 1.0.0
angularUI 0.1.0
Chrome 20

Please take a look at this line in the Select2 directive. This is a note to ANYONE writing a directive / implementing a plugin in AngularJS (not just AngularUI):
Any plugin that injects a new DOM element immediately after the linked element runs the risk of disrupting the compiler. The reason is because the way AngularJS works, it caches the index of each DOM element at compile time, and then makes a second pass upon linking. When you inject new DOM, you offset the index of all siblings immediately after the directive.
For this reason, I've been forced to wrap both TinyMCE and Select2 in a setTimeout so that the DOM is injected after the linking is done. Note that I don't bother using $timeout because I really don't need/want $apply() to fire just to turn on the plugin, as there are already callbacks in place that do this when the plugin changes the data.
I'll look into making sure this is uniform across AngularUI. Unfortunately, there appears to be no elegant solution to this problem in AngularJS at this time, however it's a problem I've been thinking about for some time and am constantly looking for a better solution towards.
Read this Google Groups post for more information about compiling vs linking: https://groups.google.com/forum/?fromgroups#!searchin/angular/compile$20link/angular/RuWn5W3Q5I0/KJhcQJ_RNsIJ
You can also open a bug ticket on the AngularUI project in the future.

As suggested by Pete BD in his comment on the question, there is some kind of bug/unwanted behaviour in the way that jQueryUI and angularJS interact. A workaround is to wrap the input control in a div.
<div class="date">
<label for="projectSearchDateFrom"><%= Res("Projects.Search.From")%></label>
<div>
<input id="projectSearchDateFrom" type="text" ng-model="startDate" ui-date="dateOptions"/>
</div>
<img class="clear" ng-show="hasStartDate()" ng-click="clearStartDate()" src="/_Layouts/ClientPortal/Images/layout/TA/delete-small.png" alt="<%= Res("ToolbarDialog.Clear")%> <%= Res("Projects.Search.From")%>" title="<%= Res("ToolbarDialog.Clear")%>" />
</div>
Now I can use showOn "both" or "button".

This is fixed in the latest release!

Related

Using a CSS class, but can't find where it is defined

I have been searching for an easy way to make a month/year picker for an ASP.NET Core application I'm making. I found this fantastic one on jsfiddle. It uses the following resources:
bootstrap-datepicker.min.js
datepicker.min.css
bootstrap.min.js
bootstrap.min.css
Here is the code:
var startDate = new Date();
var fechaFin = new Date();
var FromEndDate = new Date();
var ToEndDate = new Date();
$('.from').datepicker({
autoclose: true,
minViewMode: 1,
format: 'mm/yyyy'
}).on('changeDate', function(selected) {
startDate = new Date(selected.date.valueOf());
startDate.setDate(startDate.getDate(new Date(selected.date.valueOf())));
$('.to').datepicker('setStartDate', startDate);
});
$('.to').datepicker({
autoclose: true,
minViewMode: 1,
format: 'mm/yyyy'
}).on('changeDate', function(selected) {
FromEndDate = new Date(selected.date.valueOf());
FromEndDate.setDate(FromEndDate.getDate(new Date(selected.date.valueOf())));
$('.from').datepicker('setEndDate', FromEndDate);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<link href="https://netdna.bootstrapcdn.com/bootstrap/3.0.3/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://netdna.bootstrapcdn.com/bootstrap/3.0.3/js/bootstrap.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datepicker/1.3.0/css/datepicker.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datepicker/1.3.0/js/bootstrap-datepicker.min.js"></script>
<div class="form-group">
<label>First check in:</label>
<input type="text" class="form-control form-control-1 input-sm from" placeholder="CheckIn">
</div>
<div class="form-group">
<label>First check out:</label>
<input type="text" class="form-control form-control-2 input-sm to" placeholder="CheckOut">
</div>
<br/>
<div class="form-group">
<label>Second check in:</label>
<input type="text" class="form-control form-control-1 input-sm from" placeholder="CheckIn">
</div>
<div class="form-group">
<label>Second check out:</label>
<input type="text" class="form-control form-control-2 input-sm to" placeholder="CheckOut">
</div>
I have made this work in my project in Visual Studio, however, it doesn't seem to be able to find the classes "form-control-1" (and 2) and "from" and so it gives me a little squiggly line indicating so.
I started looking through all the css files included and I cannot find a reference to those classes in any file. If I remove them, the month selector does not work. Can someone help me understand where that functionality is coming from? Does anyone know where those classes are defined?
The from and to are not being used for styling, they are being used in the code that you posted. $('.from').datepicker() $('.to').datepicker().
You can safely delete the form-control-1 and form-control-2 classes.
Those classes can be fuctional classes, not attached to any styling but used to select or manipulate the elements.
Thats probably why you wont find anything. Search through the js files and you will find something.
Since removing the class breaks the functionality, it's probably being referenced from JS. It may be that the JS is calculating the name of the class, something like "form-control " + i for example.
Your best bet to see where this is defined is to use the browser inspector. For example, in Chrome, right-click the page and choose "inspect" to get this UI, which shows you each css class and where they are declared or re-declared in the css hierarchy.
When using Javascript it can be very useful to use CSS classes which are not attached to any styling, but are instead used as semantic references for jQuery selectors to use later.
This can be very useful when trying to attach multiple semantic meanings to an element. You can have one element can have many semantic tags. I use this in complex components to be able to dynamically tag elements that I can later manipulate or check the class name. This is especially useful if you are generating elements from a server-side language and trying to tag them semantically so that they can be manipulated later from Javascript/jQuery. It think it is much easier to add a dynamic class string from the server side than to put in data attributes.
One example of this that I use is for validation information to be attached to an element. I generate the elements in a server-side class (including what type of validation it should have) which outputs a CSS class string, then when I submit the form in Javascript, I get all elements with specific classnames and check if their contents match the validation type.
The code sample you posted does a similar thing, where it wants to use a jQuery plugin on all elements with a certain class. Instead of direct styling, it uses them as semantic markers that those elements should be transformed in a certain way to be datepickers (which are documented here: https://jqueryui.com/datepicker/). Code for jQueryUI uses this a lot to be able to simplify which elements should be used-- and it can be easier to add new elements that are datepickers, since you simply add a class to the new one instead of having to add a new jQuery reference to it (especially if you don't know exactly how many of them there will be on the page when you write the Javscipt code).
If you are ever in a similar instance and looking for a different way to store data on elements without inadvertent effects and it is pure Javascript without server side rendering, data-* attributes in HTML5 are a way to do it (and a simple library could be developed to add them to elements from a server side language). Just use jQuery selectors with jQuery("[data-mytagname=someValue]") to select.
A word of caution that if you use classes like this as semantic tags, I would be careful to avoid commonly used class names, since you could inadvertently get extra styling when a co-worker (or yourself) decides to use that in an element. ;)

When should prefer angular directive over html native tag?

I'm a big fan of angularjs, I started lately to use it in all of my 'coding for fun' projects.
I have a big curiosity:
I have a two inputs, one disabled by a ng-disabled directive and the other disabled with an html tag (A better illustration in this link):
//...
<input type="text" disabled value="This is an html input text disabled" />
<input type="text" ng-disabled="true" value="disabled with angular js directive" />
//...
Using the browser ability I can right click on the input and remove the disabled and ng-disabled tags but only the one with the disabled tag would be editable, the other one will still be tracked by angular even when ng-disabled directives has been removed.
So, When and Why should I prefer using ng directives over native html tags? Which could be the impact of letting angular track all these actions? is it really worth to use it everywhere?
Use the native html 'disabled' if the element should always be disabled. (static, for example if you want to provide an input with text and never let the user change it)
Use angular if it should change based on variables value in the scope.
For example, say a button should change the state of an input.
<input type="button" ng-click="inpDisabled = true" >Disable Input</input>
<input type="text" ng-disabled="inpDisabled" />
live example
No harm will come if you still use ng-disabled="true" but it's redundant.
If you want to make directive static, you shoud use native html
<your-tag disable><your-tag>
against
<your-tag ng-disabled="true"><your-tag>
But AngularJS does not work this way, you shoud initialize your application and controller, then pass a variable as parameter to your directive:
JS:
$scope.isDisabled = true;
HTML:
<your-tag ng-disabled="isDisabled"><your-tag>
You shoud read more tutorials to make things clear

Change text input value with jQuery - Chrome extension

I am trying to change input value in particular web site from chrome extension. In order to do that I am using jQuery in my content script. It works in most of the cases, but I didn't manage to change value of the input when it is part of AngularJS view. I found the same problem when I use let say kendoUI. I am trying to set the value calling $('element').val('value') and then try to call blur and change event, but without any success.
I went through may be 99% of the posts related to this topic, but still can't find working solution.
You just need to Call $scope.apply() in order to let angular know about updating the bindings. This is mainly because by default, angular doesn't know anything about the changes you are making in jQuery.
Below is a sample code, and here is a jsFiddle. Hope this helps.
app.controller('testCtrl', ['$scope', function ($scope) {
$scope.changeValue = function() {
$('#test').val("new Value");
$scope.apply();
}
<div class="form-inline">
<input type="text" id="test" value="test">
<input type="submit" value="submit" ng-click="changeValue()">
</div>

Angular directive inserts wrong DOM node

I have an app with many forms. Each field has several HTML elements, so I thought I could extract some directives (one per type of field) to keep my forms tidy.
I've created a sample app to demonstrate the problem, but I'm getting inconsistent behavior. In the sample app, a <link /> element replaces the <input />. In my real app, <input /> just gets removed from the DOM completely. I feel like this should be easy; why doesn't it work?
To answer your stated question, it's because you told it to, with ng-transclude. That replaces the contents of the tag with the original element, which I don't think you wanted; you probably wanted the original contents to be transcluded as the label instead.
This is probably what you're looking for:
<div class="form-group" >
<label for="{{htmlId}}" ng-transclude></label>
<input id="{{htmlId}}" class="form-control" type="text" ng-model="model" />
<span ng-repeat="error in errors">{{error}}</span>
</div>
I've moved the tranclusion into the label. While this works, I would also recommend the style of actually passing a label attribute, rather than transclude it, just for the sake of having a consistent API and simpler code; it's functionally equivalent, though, so don't let me bully you.
Also, you've got a few errors in your .js as well. First, you want to use = in your scope instead of &
scope: {
model: '=',
errors: '='
},
& is used to pass methods, while = is used for objects (this is a simplification). Since your model and errors are objects, you'll want to use = instead.
Finally, in your example, your html template and your directive's template don't have the same name... you've got an extra 's' in your .js, but that's probably just in the plunker and not your real app.

AngularJS ng-click fires twice

I am using ng-click and it fires twice when I apply it to SPAN tag.
HTML
<div ng-app="regApp" ng-controller="RegistrationCtrl" data-ng-init="GetEventDetail()" ng-show="data.EventName">
<h2>Registration for {{data.EventName}}</h2>
<span class="btn" id="btnSave" ng-click="PostRegistration()">Save </span>
</div>
CONTROLLER
var app = angular.module('regApp', ['ui']);
app.controller('RegistrationCtrl', function ($scope, $http) {
$scope.PostRegistration = function () {
alert('click '); <--- fires twice
/// some code here --
};
It should only fire once. How I can find why this is happening and how to fix it?
The code you've provided does not fire the event twice:
http://jsfiddle.net/kNL6E/ (click Save)
Perhaps you included Angular twice? If you do that, you'll get two alerts, demonstrated here:
http://jsfiddle.net/kNL6E/1/
I had a similar problem, but could not find where I included Angular twice in my files.
I was using an ajax calls to load specific form layouts, so I need to use $compile to activate Angular on the inserted DOM. However, I was using $compile on my directive $element which has a controller attached. Turns out this "includes" the controller twice, causing two triggers with ng-click or ng-submit.
I fixed this by using $compile directly on the inserted DOM instead of my directive $element.
Same problem using
<a ng-click="fn()"></a>
fn was called twice
Using a button fixed it :
<button ng-click="fn()"></button>
This is probably obscure, but I had ng-click firing twice because I had BrowserSync running, which would mirror my inputs into a tab that I had open in another window, thus doubling up all my clicks. To resolve, I disabled “ghostMode”: https://www.browsersync.io/docs/options/
I solved this by removing my ngsubmit handler as I don't have a need for it. I'm monitoring on change events and using SignalR to update the screen in near real-time.
I was also in a form and the AngularJS docs for ngSubmit states:
Warning: Be careful not to cause "double-submission" by using both the ngClick and ngSubmit handlers together. See the form directive documentation for a detailed discussion of when ngSubmit may be triggered.
In case of somebody having the same issue:
This was my problem:
<a type="submit" ng-click="login()">submit login<a>
Both, the type="submit" and the ng-click="login()"triggered the login()-method in my controller.
So just use either the type=submit or the ng-click directive
If other answers don't help, make sure that AngularJS profiling is disabled in Batarang (if you have it installed of course).
This was making ng-click to fire twice for me.
elements wrapped one another, and this can cause trigger event twice or more.
So i used a simple CSS trick for this solution :
.off{
pointer-events:none;
}
and apply it to an element correspond to click event.
You might have a ng-click inside a form container using a ng-submit. In that case, add type="button" to all your using ng-click.
I got it when I accidently called $compile for the dynamically added elements several times in the cycle, instead of just once. Compiling just once removed this effect.
was facing same issue.
Find out they were using https://ajax.googleapis.com/ajax/libs/angularjs/1.0.8/angular.min.js version and i switch it to latest 1.4.5 version and it just worked.
https://ajax.googleapis.com/ajax/libs/angularjs/1.4.5/angular.min.js
var app = angular.module('regApp', []);
app.controller('RegistrationCtrl', ['$scope','$http',function($scope,$http ) {
$scope.PostRegistration = function() {
alert('click '); // <--- fires twice
/// some code here --
};
}]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="regApp" ng-controller="RegistrationCtrl">
<h2 >Registration for {{data.EventName}}</h2>
<span ng-click="PostRegistration()" class="btn" id="btnSave">Save </span>
</div>
I have changed <button ng-click='clickHandler()'> to <a ng-click='clickHandler()'> and now event fires only once
I've had the same issue when dynamically injecting partial views in my SPA(Single Page Applications).The way I solved it was to store the content of my div in a local variable like this:
var html = $("#leftContainer").html();
Then empty out the div and reset its content like this:
$("#leftContainer").empty();
$("#leftContainer").append(html);
Now you can add any additional html you have received from an AJAX call or dynamically constructed and lastly remember to re-compile your HTML to make it bound to angular:
var entities = $("#entitiesContainer");
var entity = "<div><a href='#' ng-click='Left(" + entityId + ")'> " + entityName + "</a><div>"
entities.append(entity);
var leftContainer = angular.element(document.getElementById("entitiesContainer"));
$compile(leftContainer)($scope);
I'm a bit of a dummy and had this:
<li data-shape="amethyst" ng-click="toggleGem('amethyst')">
<label></label>
<i class="amethyst"></i>Amethyst
<input type="checkbox" name="gem_type" id="gem-amethyst" value="amethyst" />
</li>
The click event was triggering twice. I moved the ng-click to the label element and it's working as expected.
<li data-shape="amethyst">
<label ng-click="toggleGem('amethyst')"></label>
<i class="amethyst"></i>Amethyst
<input type="checkbox" name="gem_type" id="gem-amethyst" value="amethyst" />
</li>
This situation may be caused by lacking the ngTouch in Angular.
Event if the ngTouch is loaded, the bug in ngTouch and ngClick before Angular 1.5.0 may occur. It results from the ngClick being triggered by pointerup and mouseUp in Chrome for Desktop on device toolbar or mobile device.
I had a problem like this as well.
<button style="width: 100%;" class="btn btn-danger" ng-click="'{{vm.delete()}}'">
Thats not how you call ng-click, but no errors were thrown and the function calls still worked.
<button style="width: 100%;" class="btn btn-danger" ng-click="vm.delete()">
Is correct and will then only be called once.
I don't know what was the reason this happened, but I had to use event.stopPropagation(); inner my JavaScript function.
HTML
<button class="button" ng-click="save($event)">Save</button>
JAVASCRIPT
function save(event) {
event.stopPropagation();
}
I have handled it by following code
HTML :
<div>
<ui>
<li>
<button class="Button" ng-disabled="self.desableSubmitButton" ng-
click="self.SubmitClick($event)">Submit</button>
</li>
</ui>
</div>
Angular 1.0 Controller :
_self.SubmitClick = function(event){
_self.desableSubmitButton = true; //disable submit button
event.preventDefault();
event.stopPropagation();
setTimeout(funtion() {
_self.desableSubmitButton = false; //enable submit button after timeout
if(_self.$scope.$$phase != '$apply' || _self.$scope.$$phase != '$digest'){
_self.$scope.$digest();
}
}, 1000);//other Code logic
}
My case: I used ng-click event on my custom custom angular checkbox component. So just providing a method binding for custom component did the trick.
Before:
<mono-checkbox-ng ng-click="vm.onSelectAllClicked()">
After:
<mono-checkbox-ng on-changed="vm.onSelectAllClicked()">

Categories

Resources