Angular Apply already in progress - javascript

I am using an angular js plugin called intro.js. It can be found here. What I want to do with this is open up a dropdown when the user clicks on the demo button so that I can show some intro steps for the dropdown items. Here's my html:
<body ng-controller="MainCtrl as ctrl">
<div ng-intro-options="ctrl.IntroOptions"
ng-intro-method="ctrl.CallMe">
<div class="container">
<button class="btn btn-success"
ng-click="ctrl.startHelp()">Help</button>
</div>
</div>
</body>
And my JS:
MainCtrl.prototype.startHelp = function() {
var _this = this;
angular.element('#drop-down-button').trigger('click');
_this.CallMe();
};
I've also tried
angular.element('#drop-down-button').click();
But the same error. The intro works just fine if i remove the angular.element line. However, with that included I get this error. Any idea how to get around this?

I just had to wrap the call inside of a timeout.
MainCtrl.prototype.startHelp = function() {
var _this = this;
_this.$timeout(function() {
angular.element('#drop-down-button').trigger('click');
}, 0, false);
_this.CallMe();
};

Related

How to replace a child div on it's existing parent div using angularjs?

I have the following code.
html:
<div ng-controller="Test">
<div ng-click="first()" ng-hide="seconddiv">First
<div ng-click="second()" ng-show="seconddiv">Second</div>
</div>
</div>
js:
var app = angular.module('app',[]);
app.controller('Test',function($scope){
$scope.first = function(){
alert("first clicked");
}
$scope.second = function(){
alert("second clicked");
}
});
On executing the above code:
a). I should see only First by default(I can see one now: First) - it is fine now
b). then, if I click on First, then it should execute it's first() method, then First should be replaced with Second(on UI) - it's not coming
c). then, if I click on Second, then it should execute it's second() method only, (it should not execute any other methods like first() except second() method) - it's not coming
I request you to please help me regarding this that how can we do this? Thanks in advance!
Please note that Html <div> structure should not change, so it should be same.
Created Fiddle .
Go the Angular Way.
You will have just one function, toggle. Which will toggle the value of variable first from true to false and vice versa.
Depending on value of first you will show either div with content as First or that with content as Second.
You will also refactor your HTML a bit as follows
<div ng-controller="Test">
<div ng-if="first" ng-click="toggle()">First</div>
<div ng-if="!first"ng-click="toggle()">Second</div>
</div>
And in your JS you will do
var app = angular.module('app',[]);
app.controller('Test',function($scope){
$scope.first = true;
$scope.toggle = function(){
$scope.first = !$scope.first;
}
});
====
EDIT:
Alternatively, you don't even need the toggle function. Just use ng-click expression.
<div ng-controller="Test">
<div ng-if="first" ng-click="first=!first">First</div>
<div ng-if="!first"ng-click="first=!first">Second</div>
</div>
And in JS
app.controller('Test',function($scope){
$scope.first = true;
});

Understanding the working of ngClick and ngDblclick

I was trying to figure out how ngClick and ngDblclick work in angularjs. The problem is that even while clicking twice, instead of calling doubleclick function once. Angular calls click function twice and double click function once.
HTML:
<div ng-controller="MyCtrl">
<div class="button" ng-click="click()" ng-dblclick="dblclick()">
Click
</div>
<div class="button" ng-click="reset()">
Reset
</div>
<div>
clicked:{{clicked}}
</div>
<div>
double clicked : {{dblclicked}}
</div>
</div>
JS:
var myApp = angular.module('myApp',[]);
function MyCtrl($scope) {
$scope.clicked = 0;
$scope.dblclicked = 0;
$scope.click = function(){
$scope.clicked++;
};
$scope.dblclick = function(){
$scope.dblclicked++;
};
$scope.reset = function(){
$scope.clicked = 0;
$scope.dblclicked = 0;
};
}
JsFiddle here
But this is not the case in jQuery wherein $(someElement).click() and $(someElement).dblclick() work as expected, which seems to be the ideal way to do it.
I have a fair idea that this is happening because they are implemented as directive in angular. Wherein in jQuery it works by listeners.
I see that you can eliminate this by using $evalAsync, but what reckons me is why we need such an extra burden to achieve something which is very obvious.
Can someone tell me how to handle the scenario. Thanks in advance.

adding items to an array in async call does not not update angular 1.5.8 view

Plunkr here:
https://plnkr.co/edit/aWBE55?p=preview
Let's say I have a view like this:
<body>
<div ng-app="myApp">
<div ng-controller="myAppController as app" >
<input type="text" ng-model="app.colorName" /><button ng-click="app.addColor()">add color</button>
<div ng-repeat="c in app.colors">{{c.colorName}}</div>
</div>
</div>
</body>
and I have a controller like this:
var Color = function(options) {
var self = this;
self.colorName = options.colorName;
};
(function(angular) {
'use strict';
angular.module('myApp', []).controller('myAppController', function myAppController($filter) {
var self = this;
self.colorName = '';
self.colors = [
new Color({colorName: 'Red'}),
new Color({colorName: 'Blue'}),
new Color({colorName: 'Green'})
];
self.addColor = function() {
console.log("added a new color " + self.colorName);
self.colors.push(new Color({colorName: self.colorName}));
};
setTimeout(function() {
console.log("added new color in another thread");
self.colors.push(new Color({colorName: 'Purple'}));
}, 1000);
});
})(window.angular);
See that little setTimeout guy pushing another color onto the array? It seems that because it's being added from an async call (because of the setTimeout), the view does not refresh immediately and show the Purple color after it's been added.
Interestingly, even clicking into the textbox and then out (which touches that ng-model property) triggers a view update and 'Purple' appears... and, of course, adding a color by pushing the button refreshes the view immediately.
Why does this happen and what should I do about it?
I could do $scope.$apply, but that seems particularly hideous as the real world example (which involves modal dialogs with callbacks) is component-based and trying to get away from doing $scope-y things. This example was worked up for simplicity.

Showing div in angularjs not working

I want to show a div only when the function happens.
Here is the HTML, but it is always showing, I want it to show only when the function is true
<div ng-controller="controller">
<div ng-show="data.show"> Successfully triggered </div>
<div ng-hide="!(data.hide)"> Error in triggering</div>
</div>
In the controller I have:
if(results.data=='success') {
$scope.data = {
show: false,
hide: true
};
//Here I should display the success message
} else {
//Here I should display the error message
}
So, How can I show the success div in if condition and error div in the else condition.
Note : If possible if the div is shown in slow motion it will be very helpful for me. Like the fade timing in jQuery.
You should only maintain only one flag data.show that is more than sufficient to show hide div.
<div ng-controller="controller">
<div ng-show="data.show"> Successfully triggered </div>
<div ng-hide="data.show"> Error in triggering</div>
</div>
Controller
app.controller('myCtrl', function(){
///other stuff here ..
$scope.myFunction = function(){
if(results.data=='success') {
$scope.data.show = true; //success
} else {
$scope.data.show = false; //error
}
}
//init code here
$scope.data = { show: false }; //this should be outside your show/hide function
})
I would use one div something like the following
<div ng-controller="controller">
<div ng-show="data.show">{{data.message}}</div>
</div>
Get rid of your hide property on data it isn't needed and set your text in the controller on another data property. The bottom line is data.show has to be "truthy" for the div to show up. Honestly, if you are always going to show a div I would get rid of ng-show and just dynamically set the div content in the controller.
here is my example: Example for show div on jsfiddle
<div ng-app>
<div ng-controller="showCtrl">
<div>Show Div:
<button ng-click="set()"></button>
<div ng-show="showDiv"> Successfully triggered </div>
<div ng-hide="showDiv"> Error in triggering</div>
</div>
</div>
</div>
If you want to add fade in and fade out timing, I suggest you to look up angular animate. Documentation and example for angular animate.
wow, there are already so many answers, and they are all correct. Everybody also rightly pointed out that to have a little animation, you can use ngAnimate.
My little jsFiddle is here, just as a fun little exercise.
var app = angular.module('app', ['ngAnimate']);
app.controller('testCtrl', function ($scope) {
$scope.data = {
show:true,
hide: false
};
$scope.go = function(checked) {
$scope.data = {
show:!checked,
hide: checked
};
}
});
https://jsfiddle.net/dshun/j8wgnnm5/13/

Polymer autogrow textarea focus() not working

I am using polymer's iron-autogrow-textarea. I was able to set the autofocus attribute and its working perfectly fine.
But when I try to set the focus back to textarea it doesn't seem to work.
I have tried
autoTextArea.focus();
It didn't work
setTimeout(function() {
$('#autoTextArea')[0].focus();
}, 1000);
This didn't work
setTimeout(function() {
$('#autoTextArea')[0].setAttribute('autofocus', true);
}, 1000);
This obviously didn't work as autofocus only works on ready().
I have also tried to access the textArea inside the autogrow-textarea and even that didn't seem to be working.
Is there a way this can be done?
Thanks in advance.
Here is the code snippet where I am using it.
'click #chatEnter': function(e, template) {
var chatArea = $('#chatArea')[0];
var chatTextArea = $('#chatTextArea')[0];
if(chatTextArea.bindValue)
{
var chatNode = document.createElement('chat-message');
chatNode.setAttribute('color', '#ff00ff');
chatNode.setAttribute('avatar', '/src/someimage.jpg');
chatNode.setAttribute('username', 'SomeName1');
chatNode.setAttribute('text', chatTextArea.bindValue);
chatNode.setAttribute('status',"MyStatus");
chatNode.setAttribute('timestamp',"2015-07-12 12:00:00 AM");
chatArea.appendChild(chatNode);
chatTextArea.bindValue = "";
setTimeout(function() {
$('#chatTextArea')[0].setAttribute('autofocus', true);//.focus();
}, 1000);
}
Here is the HTML where I am using it.
<section main layout vertical id="chat">
<paper-material id="chatArea" elevation="1" animated style="overflow-y:scroll">
</paper-material>
<span layout horizontal>
<paper-toolbar class="medium">
<div>
<iron-autogrow-textarea label="Enter message here" autocomplete="true" autofocus="true" maxRows=5 name="Text Area" id="chatTextArea">
<textarea id="chatText" max-rows="5" ></textarea>
</iron-autogrow-textarea>
</div>
<paper-icon-button raised icon="send" id="chatEnter"></paper-icon-button>
<iron-a11y-keys keys="ctrl+enter" on-keys-pressed="[[enterKeyHandler]]"></iron-a11y-keys>
</paper-toolbar>
</span>
</section>
You don't need to put a textarea tag inside iron-autogrow-textarea. The iron component is providing one. You can then access that inner textarea via .textarea and call focus on it.
Here's a small working example.
<body>
<iron-autogrow-textarea rows="5"></iron-autogrow-textarea>
<button>Focus!</button>
<script>
var button = document.querySelector('button');
button.addEventListener("click", function(){
console.log(document.querySelector('iron-autogrow-textarea'));
var area = document.querySelector('iron-autogrow-textarea');
area.textarea.focus();
});
</script>
</body>
Had a very similar problem - when I navigated the page, the focus didn't return to the paper-textarea the second time I visited. After some looking at the DOM I came to the following solution:
//focus textarea
setTimeout(() => {
//first working solution, line after that a bit more general
// this.$.idOfPaperTextarea.shadowRoot.querySelector('paper-input-container').querySelector('#input-1').shadowRoot.querySelector('#textarea').focus();
this.$.idOfPaperTextarea.shadowRoot.querySelector('iron-autogrow-textarea').shadowRoot.querySelector('textarea').focus();
}, 0);
I guess the problem is that you have to get through the shadowRoots to access the textarea.

Categories

Resources