angularjs: setting focus on a previously-hidden input element inside a directive - angularjs

Here is a simplified plunk to illustrate the problem
I got an angular directive that compiles some html code before visualizing it. In the html, there is an hiden input that becomes visible only if scope.isEditShown is true:
<input ng-show='isEditShown' type='text' value='{{content.name}}' class='title_edit'/>
The input appears when the scope.titleChange function is invoked. This function (bound to an ng-dblclick directive) just sets true to scope.isEditShown and tries to invoke jQuery's focus() method on the input element (previously stored in the scope in the linker function with scope.input = $("input:text", ae);:
scope.isEditShown = true;
scope.input.focus();
In short, I want to visualize a previously-hidden input when something is double-clicked, and give it immediate focus. The immediate focus is needed because the input is hidden when it loses focus (I want the user to immediatly be able to edit the input content. When the user clicks away, the input is hidden).
The problem is that it seems I can't give the focus to the input element programmatically.
After experimenting, I found that when scope.isEditShown = true; is executed, the input is not visible yet (= angular js doesn't show it in the DOM), and setting focus with scope.input.focus(); to a hidden input does nothing. When the input element finally gets shown, it's unfocused.
What is the angular way to do what I want? When can I be sure that my input is shown and when can I call focus() on it effectively? NOTE: if I use scope.$apply() before giving focus to the input, I will get $apply already in progress exception. If I do a safe apply, foucus won't be given. See the plunkr.
(ps: I really want to understand, so I'm not gonna use companion libreries that automagically do that for me)

When you make changes to some data-bound variable and you need to wait for the corresponding rendering to happen, you need to use the famous setTimeout 0 ( alternately in Angular the $timeout service ).
Here is a plunkr that shows how to do this.
http://plnkr.co/edit/N9P7XHzQqJbQsnqNHDLm?p=preview

Related

md-checkbox does not get set by ng-model value inside a directive's link() function

I'm building a questionnaire out of directives which show the correct input based on certain expectations. Those expectations (including any formerly given input from the user) comes from a parent $scope. Everything is set up in the link function of AngularJS's directive definition object
Where things go wrong is when using md-checkbox: the ng-model of the checkbox inside the directive is set to true, the md-checkbox is still false. I can confirm that by adding a simple input type="checkbox" with the same ng-model property, the simple checkbox is checked, whereas the md-checkbox isn't.
Whenever I click on the md-checkbox twice, it does get checked. So I gather that there is something wrong with the binding. I built a CodePen which demonstrates it. The code inside the pen is almost taken verbatim from my source code
Stuff that I already tried:
Using $scope.$apply() after handling all (DOM) logic in the link function
Idem but with $scope.$digest()
Setting a $timeout with no delay (as way of a 'safe' $apply())
Even going so far as to store the current answer (true or false) in a variable, setting the ng-model property to undefined, and then setting it back to the stored value, all inside a $timeout
I'm at loss here, it looks like something simple given the fact that all the other inputs have their correct data in it.
Replace class with ng-class because ng-class lets you to dynamically bind the class to the element
Depending on your codepen the problem is class="md-checkbox-{{expression}}". I forked your codepen. You can use ng-class. I think this is a bug.

How to test current input selectionRange/cursorPosition in the Protractor.js?

I just learn how to create angular.js directives.
I write simple directive for input with two-way binded selectionRange control.
When scope variable changes - selection range inside the input changes too.
How this behavior can be tested with Protractor.js?
I can not to find any method to get input current selectionRange/cursor position or even selected text.
You can found&playWith my directive here: Demo
Todo with what I want to achive here: github
When you change $scope data with form below, input selection changes.
I want just cover this behavior with test, and don't know how to get current selectionRange in the protractor environment.
Referring to the problem I've recently solved with the help of #trincot:
expect(browser.executeScript("return arguments[0].value.substring(arguments[0].selectionStart, arguments[0].selectionEnd);", elm.getWebElement())).toEqual("selected part of the input text");
Here selectionStart and selectionEnd are used to get the currently selected text in an input.

Invoking a callback before or after showing a popover using angular-ui-bootstrap

I have a very simple code snipper in my page where I have a span. Hovering over this span displays a popover for which I am using angular-ui-bootstrap.
<span uib-popover="This is a popover from Akhilesh"
ng-mouseenter="vm.logToConsole('I am trying hard...')"
popover-trigger="mouseenter">Hover over me to see a popup..!!</span>
Basically I have written a function which makes and API call when the user hovers over this span. The problem here is that let's say I have 10 span tags one below the other and the user quickly moves from 1st span to 10th span (in the process hovering over all 8 spans in between), the API call will get triggered for all the spans. This is what I do not intend to have.
Any idea how can I implement the debounce functionality here?
Use a delay, like one second, after the mouse enters the region, then if the mouse hasn't entered another area, make the API call.
The popover-is-open attribute was added under the 0.13.4 release that can be used to watch the state of your popover like so:
<span uib-popover="This is a popover from Akhilesh"
popover-is-open="vm.isOpen"
popover-trigger="mouseenter">Hover over me to see a popup..!!</span>
Then in your controller:
$scope.$watch('isOpen', function() { });
But if you are just trying to keep the popovers from opening so quickly, consider using the popover-open-delay attribute.
Depending on your use, I found the best method is to simply add ng-mouseover, ng-click etc to the element and define a function to be called.
You can even create a variable and attach it to that objects scope on the fly to keep track of the state (open close).
Kind of hacky, but there is currently no way to define a function that is called on open and on close within ui-bootstrap popover.

It takes 2 clicks for change in angular directive

Ok, so I'll just start off saying I'm almost certain this bug is either arising from my lack of understanding of isolate scoping in angular directives or some weird interaction between directives and the angular google maps markers directive.
Anyways, the issue is that I have an instance of the angular-google-maps stuff in my main controller, and I have a tag within that. I also have a directive which is captures user inputs and uses them to populate a list in the main controller for the tag to do its thing. I pass in an object and function from the main controller into the directive's isolate scope.
The weird thing is that within my directives, I have bound this function onto a button click for a form, and for some reason, it takes 2 clicks to get the marker to appear. The function fires the first click, it has all the right values and everything, but the marker doesn't appear. Another weird I checked was simply calling the method twice in a row for one click which didn't work (still required 2 button presses).
The function modifies the array in the main controller (I have a feeling this is the root of the issue) which is used by the tag as a list of markers. Any ideas on why this could be happening? If it doesn't seem like an obvious misunderstanding of Angular scoping, I can post code.
My first thought is your data is happening outside of the digest loop. And if that's the case then adding a $scope.$digest() after your data is updated might solve it (or give you a console error).

hidden elements in angularJS not compiled

I have a popup in my application that is hidden when page is loaded and it appears only on click on a specific button.
I have the following code inside my popup DOM
<a ng-click="settings();">welcome</a>
The same code works when i have it in my DOM that is visible when the page loads. But inside the popup, it does not work. It never goes inside the settings() function. Can anyone help me with this?
You should probably create a directive for it. See the documentation and this example. Notice that a scope is applied to the return value of the compilation, effectively var compiled=$compile(element.contents()); compiled($scope);.
Note that there is already a built-in include directive in Angular which might do what you want. The example there responds to changes in a drop down, though you could easily adjust it to respond to a click event.

Resources