Combine $timeout and $interval in AngularJS - angularjs

I am trying to make a button that executes a action immediately after he was clicked. But if the mouse is still down after a timeout the action should be repeated as long as the button is down.
In the following code the $interval is working. But somehow the $timeout gets ignored and the interval starts immediately. What am I doing wrong?
angular
.module('myApp', [])
.controller('myController', ($scope, $timeout, $interval) => {
var interval;
var timeout;
let main = $scope;
main.times = 0;
let promise;
let doSomethingOneTime = () => {
$scope.times++;
};
let doSomethingInfinitely = function() {
promise = $interval(function() {
doSomethingOneTime();
}, 100)
};
main.mouseDown = function(action) {
doSomethingOneTime();
$timeout(doSomethingInfinitely, 5000);
};
main.mouseUp = function() {
$interval.cancel(promise);
};
});
<!DOCTYPE html>
<html ng-app='myApp'>
<head>
<script data-require="angular.js#4.0.0" data-semver="4.0.0" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.10/angular.min.js"></script>
<script data-require="angular.js#4.0.0" data-semver="4.0.0" src="script.ts"></script>
<script data-require="angular.js#4.0.0" data-semver="4.0.0" src="system.config.js"></script>
<script data-require="angular.js#4.0.0" data-semver="4.0.0" src="tsconfig.json"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body ng-controller='myController'>
<button ng-mousedown="mouseDown()" ng-mouseup="mouseUp()">Mouse Down</button>
<br>
<span>Doing something {{times}} times</span>
</body>
</html>

The problem is two fold. The first case is that if you mouse up before the timeout delay has finished, the interval promise you set will still be undefined, thus when you call cancel nothing is cancelled. The second problem is if you click the button twice you will lose all reference to the first interval promise. The second click, which creates a second timeout will replace the first interval promise when it finishes. In effect you'll have 2 $intervals executing concurrently, one of which you have no reference to.
Here is a working example.
angular
.module('myApp', [])
.controller('myController', ($scope, $timeout, $interval) => {
var interval;
var timeout;
$scope.times = 0;
$scope.mouseUp = function(){
$timeout.cancel(timeout);
$interval.cancel(interval);
};
let increment = ()=>{
$scope.times++;
};
$scope.mouseDown = function(){
increment();
timeout = $timeout(()=>{
interval = $interval(()=>{
increment();
},100)
}, 1000)
};
});
<!DOCTYPE html>
<html ng-app='myApp'>
<head>
<script data-require="angular.js#4.0.0" data-semver="4.0.0" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.10/angular.min.js"></script>
<script data-require="angular.js#4.0.0" data-semver="4.0.0" src="script.ts"></script>
<script data-require="angular.js#4.0.0" data-semver="4.0.0" src="system.config.js"></script>
<script data-require="angular.js#4.0.0" data-semver="4.0.0" src="tsconfig.json"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body ng-controller='myController'>
<button ng-mousedown="mouseDown()" ng-mouseup="mouseUp()">Mouse Down</button>
<br>
<span>Doing something {{times}} times</span>
</body>
</html>

Related

pass data to angular controller from a global function

See example below and the TODO in the send function : How can I assign the label value in the global send function to dropboxController dropbox.label
<!DOCTYPE html>
<html>
<head>
<script src="http://apps.bdimg.com/libs/angular.js/1.4.0-beta.4/angular.min.js"></script>
<script src="http://code.jquery.com/jquery-2.1.4.min.js"></script>
<script src="script.js"></script>
<link rel="stylesheet" href="style.css" />
<script type="text/javascript">
window.onload=function() {
$('#AddIn').append("<div ng-app='dropboxApp' ng-controller='dropboxController as dropbox'>{{dropbox.label}}</div>");
angular.module('dropboxApp', [])
.controller('dropboxController', function () {
var dropbox = this;
dropbox.label = "hello angular";
});
angular.bootstrap($('#AddIn'), ['dropboxApp']);
}
function send(label)
{
//TODO assign label value to dropboxController dropbox.label
}
</script>
</head>
<body>
<div id="AddIn"></div>
<button onclick="send('new label');">Send</button>
</body>
</html>
Use angular.element and get scope of specific dom element and apply label to it.
Change dropbox.label to $scope.label and inject $scope in controller because this and $scope are different. Check 'this' vs $scope in AngularJS controllers
Keep in Mind: Here I have used myDiv which has scope for angular and added id in append div line.
It's better to use ng-click instead of onclick if possible.
window.onload = function() {
$('#AddIn').append("<div id='myDiv' ng-app='dropboxApp' ng-controller='dropboxController as dropbox'>{{label}}</div>");
angular.module('dropboxApp', [])
.controller('dropboxController', function($scope) {
var dropbox = this;
$scope.label = "hello angular";
});
angular.bootstrap($('#AddIn'), ['dropboxApp']);
}
function send(label) {
var scope = angular.element($("#myDiv")).scope();
scope.$apply(function() {
scope.label = label;
})
console.log(scope.label);
}
<!DOCTYPE html>
<html>
<head>
<script src="http://apps.bdimg.com/libs/angular.js/1.4.0-beta.4/angular.min.js"></script>
<script src="http://code.jquery.com/jquery-2.1.4.min.js"></script>
</head>
<body>
<div id="AddIn"></div>
<button id="myButton" onclick="send('new label');">Send</button>
</body>
</html>

How do you set up a relationship between properties of two angular controllers?

Say I've got AdamController as adam and AnujController as anuj. I want anuj.anujProp to have a j appended to it every time adam.adamProp changes.
How could this be done? What is the best way?
Here are 4 possible ways that I came up with. I ranked them in the order that I personally feel is best.
Events - http://plnkr.co/edit/4AD8e47DaOSuutrphIkN?p=preview
Method on a Factory - http://plnkr.co/edit/Vixab8LjDtow5YYfnlMV?p=preview
Factory + $watch - http://plnkr.co/edit/1zVZ9EDarCGPOMZvrJMd?p=preview
$scope inheritance - http://plnkr.co/edit/3b7tzPI5Y4CcwWYXUk25?p=preview
The $scope inheritance approach just feels "messy". I like the event driven approach over the factory approaches because I feel like there's a sort of overhead associated with the factories, and if it's only going to be used for this one purpose, the overhead isn't worth it. Plus, this just seems to be exactly what events are for. I put (2) ahead of (3) because the $watch hurts performance.
Events
angular
.module('app', [])
.controller('AdamController', AdamController)
.controller('AnujController', AnujController)
;
function AdamController($rootScope) {
var vm = this;
vm.prop = 'adam';
vm.update = function() {
$rootScope.$broadcast('propChange');
};
}
function AnujController($scope) {
var vm = this;
vm.prop = '';
$scope.$on('propChange', function(event) {
event.currentScope.anuj.prop += 'x';
});
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<!DOCTYPE html>
<html ng-app='app'>
<head>
<script data-require="angular.js#1.4.6" data-semver="1.4.6" src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.6/angular.min.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body>
<div ng-controller='AdamController as adam'>
<input ng-model='adam.prop' ng-change='adam.update()'>
</div>
<div ng-controller='AnujController as anuj'>
<p>{{ anuj.prop }}</p>
</div>
</body>
</html>
Method on a Factory
angular
.module('app', [])
.factory('Factory', Factory)
.controller('AdamController', AdamController)
.controller('AnujController', AnujController)
;
function Factory() {
return {
anujProp: 'anuj',
update: function() {
this.anujProp += 'j';
}
};
}
function AdamController(Factory) {
var vm = this;
vm.factory = Factory;
}
function AnujController(Factory) {
var vm = this;
vm.factory = Factory;
}
<!DOCTYPE html>
<html ng-app='app'>
<head>
<script data-require="angular.js#1.4.6" data-semver="1.4.6" src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.6/angular.min.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body>
<div ng-controller='AdamController as adam'>
<input ng-model='initial' ng-change='adam.factory.update()'>
</div>
<div ng-controller='AnujController as anuj'>
<p>{{ anuj.factory.anujProp }}</p>
</div>
</body>
</html>
Factory + $watch
angular
.module('app', [])
.factory('Factory', Factory)
.controller('AdamController', AdamController)
.controller('AnujController', AnujController)
;
function Factory() {
return {
shared: 'shared',
related: 'related'
};
}
function AdamController(Factory) {
var vm = this;
vm.factory = Factory;
}
function AnujController(Factory, $scope) {
var vm = this;
vm.factory = Factory;
$scope.$watch('anuj.factory.related', function(newValue, oldValue, scope) {
scope.anuj.factory.related = newValue.toUpperCase();
});
}
<!DOCTYPE html>
<html ng-app='app'>
<head>
<script data-require="angular.js#1.4.6" data-semver="1.4.6" src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.6/angular.min.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body>
<div ng-controller='AdamController as adam'>
<input ng-model='adam.factory.shared'>
<input ng-model='adam.factory.related'>
</div>
<div ng-controller='AnujController as anuj'>
<p>{{ anuj.factory.shared }}</p>
<p>{{ anuj.factory.related }}</p>
</div>
</body>
</html>
$scope inheritance
angular
.module('app', [])
.controller('AdamController', AdamController)
.controller('AnujController', AnujController)
;
function AdamController($scope) {
var vm = this;
vm.adamProp = 'adam';
vm.update = function() {
var anuj = $scope.$parent.$$childTail.anuj;
anuj.anujProp += 'j';
};
}
function AnujController() {
var vm = this;
vm.anujProp = 'anuj';
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<!DOCTYPE html>
<html ng-app="app">
<head>
<script data-require="angular.js#1.4.6" data-semver="1.4.6" src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.6/angular.min.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body>
<div ng-controller="AdamController as adam">
<input ng-model="adam.adamProp" ng-change="adam.update()" />
</div>
<div ng-controller="AnujController as anuj">
<p>{{ anuj.anujProp }}</p>
</div>
</body>
</html>

firefox addon using angularJs

html file:
<html ng-app="IDAddon" ng-csp>
<head>
<link rel="stylesheet" type="text/css" href="styles/angular-csp.css">
<script src="lib/angular.min.js"></script>
<script src="scripts/app.js"></script>
</head>
<body ng-controller="MainCtrl">
<div id="somepopup">
Delayed Message: {{textmessage}}
</div>
</body>
</html>
app.js script:
function MainController($scope, suggestionService) {
$scope.getMessage = function() {
window.addEventListener("message", function (){
$scope.$apply(function() {
$scope.textmessage = 'Fetched after 3 seconds';
});
} , false);
}
$scope.getMessage();
}
var IDmodule = angular.module('IDAddon', []).controller('MainCtrl', MainController)
I can confirm that the "message" event is received and the event handler function is called, but the page never gets updated with the message.
Am I missing anything here?

Text in a button not changing on ng-click

I have a button whose text is a binding expression.
It has a ng-click directive which is a function to change the value of the expression.
However, it doesn't work.
What's wrong here?
Here is my plunk: http://plnkr.co/edit/EScqj0iczpH65tstokia
HTML
<!DOCTYPE html>
<html ng-app="test">
<head>
<script data-require="angular.js#*" data-semver="1.4.0-rc.0" src="https://code.angularjs.org/1.4.0-rc.0/angular.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body ng-controller="MyCtrl">
<button ng-click="start()"> {{ myText }} </button>
</body>
JS
angular.module('test',[])
.controller('MyCtrl',function ($scope) {
$scope.myText = 'Press to start';
$scope.start = function () {
$scope.myText = 'Starting...';
}
});
I think you got a little confused. In your script.js, you didn't define a start() function, but you called one in your ng-click directive. Instead, you created a starting() function.
This should work:
angular.module('test',[])
.controller('MyCtrl',function ($scope) {
$scope.myText = 'Press to start';
$scope.start = function () {
$scope.myText = 'Starting...';
}
});

Angular Bootstrap Slider - on stop execute function

I have the following code for creating a slider:
<html ng-app="angular-bootstrap-slider-test">
<head>
<title>Angular Bootstrap Slider test</title>
<script data-require="angular.js#1.3.0" data-semver="1.3.0" src="//code.angularjs.org/1.3.0/angular.js"></script>
<script data-require="jquery#*" data-semver="2.1.1" src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link href="bootstrap.css" rel="stylesheet" />
<link href="bootstrap-slider.css" rel="stylesheet" />
</head>
<body ng-controller="TestCtrl">
<div class="col-md-2 col-md-offset-2">
<slider on-stop-slide="executeMe();" ng-model="sliders.sliderValue" min="{{testOptions.min}}" step="{{testOptions.step}}" max="{{testOptions.max}}"></slider>
{{myFormater(sliders.sliderValue)}}
</div>
<script type="text/javascript" src="bootstrap-slider.js"></script>
<!-- angular-slider include -->
<script type="text/javascript" src="slider.js"></script>
<!-- test file include -->
<script src="app.js">
</script>
angular.module('angular-bootstrap-slider-test', ['ui.bootstrap-slider'])
.controller('TestCtrl', ['$scope', function($scope) {
$scope.sliders = {};
$scope.sliders.sliderValue = 50;
$scope.testOptions = {
min: 0,
max: 100,
step: 1,
};
$scope.sliders.thirdSliderValue = 0;
$scope.myFormater = function(value) {
return value + "%";
}
$scope.executeMe = function() {
console.log('done');
}
}]);
What i'm trying to do with no success is to execute a function when the user finishis to to move the slider
here is the code on plunker:
http://plnkr.co/edit/iULltHh0fRAbvuoFu84t?p=preview
Thanks allot
Avi
You can use ngMouseup for that.
<div class="col-md-2 col-md-offset-2" ng-mouseup="executeMe()">
<slider ng-model="sliders.sliderValue" min="{{testOptions.min}}" step="{{testOptions.step}}" max="{{testOptions.max}}"></slider>
{{myFormater(sliders.sliderValue)}}
</div>
Here's your plunkr modified to demonstrate.
Update
A different approach will be to $watch the slider's value. You can set a timeout so you don't trigger your function while sliding, but only when the value has not changed for some time.
var timeout;
$scope.$watch('sliders.sliderValue', function() {
if (timeout) {
$timeout.cancel(timeout);
}
timeout = $timeout($scope.executeMe,200);
});
See example

Resources