Start/Stop/Resume all in one button with Angular Timer - angularjs

Using the pre-built "Angular Timer" directives available here (scroll down to progress bar example), I'm trying to build a progress bar with a Start, Stop and Resume button all-in-one.
Examples on their websites are made of two buttons and I would like to merge them.
One solution could be to use innerHTML to get the current state ("Start" or "Stop") and a if condition in the controller.js but i'd like the button to be a icon-only-button switching from play to pause icon.
An example from simple timer implementation is available here
Here is my html
<button class="button button-icon icon" ng-class="{'icon ion-play': !play, 'icon ion-pause': play}" ng-click="stopResumeTimer(this)"></button>
<timer interval="1000" autostart="false"><div class="progress"> <div class="bar" style="width: {{seconds}}%;"></div> </div></timer>
And the controller.js code with the if condition
$scope.stopResumeTimer = function(btn) {
if (not yet started) {
$scope.startTimer();
}
else if (already started) {
$scope.stopTimer();
}
else {
$scope.resumeTimer();
}
}
I am discouraged by the repeated failure on this, any help would be great! Thanks

In the controller where you are setting the ng-click function, you can set flags to determine whether the click function should start, stop, or resume. Those flags can also set the text for the button to be either "Start", "Stop", or "Resume".
JS:
(function(angular) {
function controller($scope) {
var isStart = false;
var isStop = false;
$scope.timerBtnText = "Start";
$scope.timer = function() {
if (isStart) {
$scope.startTimer();
isStart = false;
isStop = true;
$scope.timerBtnText = "Stop";
return;
}
if (isStop) {
$scope.stopTimer();
isStop = false;
$scope.timerBtnText = "Resume";
} else {
$scope.resumeTimer();
isStop = true;
$scope.timerBtnText = "Stop";
}
};
}
angular.module("app", []).controller("controller", ["$scope", controller]);
})(angular);
HTML:
<button ng-click="timer()" ng-bind="timerText"></butotn>
Here is a working proof of concept: http://plnkr.co/edit/NlQFPysVH1M2EyjogQQv

This is how I would solve it (Plunker)
Controller:
app.controller('MainCtrl', function($scope) {
$scope.name = 'World';
$scope.operation = 'start';
$scope.startOrStop = function(){
document.getElementById('first')[$scope.operation]();
$scope.operation = ($scope.operation === 'start' || $scope.operation === 'resume') ? 'stop' : 'resume';
}
});
Declare it like this:
<button ng-click="startOrStop()" ng-class="{start:operation==='start', stop:operation==='stop', resume:operation==='resume'}"></button>
<timer id="first" interval="1000" autostart="false"><div class="progress"><div class="progress-bar" role="progressbar" style="width: {{seconds}}%;"></div></div></timer>
Css:
.start::before{
content:"Start";
}
.stop::before{
content:"Stop";
}
.resume::before{
content:"Resume";
}

Related

Disable link after click angular js

Could anybody help me with a solution.
I need to make the link disabled (PAY Now) after clicking on that to avoid multi clicking.
<div class="Class1" data-ng-show="ShowButton == 'TRUE'">
PAY NOW</div>
There is no disabled attribute for hyperlinks. If you don't want to do something with that you'll need to add some style into the <a> tag altogether and handle the flag into the controller.
Try this :
angular.module('myApp', [])
.controller('myCtrl', ['$scope', function($scope) {
$scope.isDisabled = false;
if($scope.isDisabled === false) {
$scope.PayNow = function() {
$scope.isDisabled = true;
}
}
}]);
.disabled {
cursor: not-allowed;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="myCtrl">
PAY NOW
</div>
You can in the PayNow() function create an extra variable which disables the button like so:
JS:
$scope.PayNow = function() {
$scope.DisabledButton = true;
// other code
}
HTML
PAY NOW
In your html
.disabled {
cursor: not-allowed;
}
<a ng-click="PayNow()" ng-class="{'disabled': DisabledButton}">Add</a>
OR
<button ng-click="PayNow()" ng-disabled="DisabledButton">Add</button>
In JS
$scope.DisabledButton = false;
$scope.PayNow = function() {
$scope.DisabledButton = true;
// other code
...
//when you want to re-enable
$scope.DisabledButton = false;
}
i hope if this can help you!!!. So in my example I am using condition to check the length of the array and constraining the button to make more textboxes. Plus you can use count instead.
$scope.technologies = [];
$scope.addtech = function () {
$scope.minus = true;
if ($scope.technologies.length < 3)
$scope.technologies.push({});
}

Teaxarea have inherent scope when i click on it is collapsing but don't let me to type my comment?

I have created already my code in here . There is three directives which each of responsible to collapse somethings.
If you execute this code you will see there is 2 panel where if you click on address is collapsing. Also if you click on comment is collapsing too. However my problem came when i want to type some comment inside textarea then is going to collapse as well. This is not what i need. I would like to click on add comment [+], then is collapsing and start to type whatever i want. I define inherent scope in script.js. I am not sure how i can change my code in order to solve this problem. I will be thank you if any of you can help me.
This is add comment directive
.directive('addComment', function() {
return {
restrict: "E",
templateUrl: "addComment.html",
scope:true,
controller: function($scope) {
$scope.collapsed = false;
$scope.collapseCom = function() {
$scope.collapsed = true;
}
$scope.extendCom = function() {
$scope.collapsed = false;
}
}
}
})
and this is my html.
<div ng-show="!collapsed" ng-click=collapseCom()>
<h4>Add Comments: [+]<br /></h4>
<div class="form-group">
<div class="col-lg-10">
<textarea name="comment" ng-model="comment" class="form-control" rows="3" required></textarea>
{{comment}}
</div>
</div>
</div>
<div ng-show="collapsed" ng-click=extendCom()>
<h4>Add Comments: [-]</h4>
</div>
To see all the details please click on following link.
replace ng-click=collapseCom()
with ng-click="collapseCom()"
$scope.collapseCom = function() {
$scope.collapsed = true;
}
$scope.extendCom = function() {
$scope.collapsed = false;
}
replace one method
$scope.collapseCom = function() {
if($scope.collapsed){
$scope.collapsed = false;
}else{
$scope.collapsed = true;
}
}
This works like switch then, and should work fine

Can ng-show directive be used with a delay

I have a spinner this is shown with ng-show="loading>0"
Is there a way I can display this spinner with a delay (say 1 second)?
I can't use a timeout because with multiple requests de loading counter will get out of sync.
What I need is a delay on the ng-show via css transition or similar
My suspicion is that you are looking for a general purpose spinner that includes a delay. The standard, show after 200ms or something like that.
This is a perfect candidate for a directive, and actually pretty easy to accomplish.
I know this is a long code example, but the primary piece is the directive. It's pretty simple.
Listen to a few scope variables and shows after some configurable delay. If the operation takes longer than the delay, it will just get canceled and never show up.
(function() {
'use strict';
function SpinnerDirective($timeout) {
return {
restrict: 'E',
template: '<i class="fa fa-cog fa-spin"></i>',
scope: {
show: '=',
delay: '#'
},
link: function(scope, elem, attrs) {
var showTimer;
//This is where all the magic happens!
// Whenever the scope variable updates we simply
// show if it evaluates to 'true' and hide if 'false'
scope.$watch('show', function(newVal){
newVal ? showSpinner() : hideSpinner();
});
function showSpinner() {
//If showing is already in progress just wait
if (showTimer) return;
//Set up a timeout based on our configured delay to show
// the element (our spinner)
showTimer = $timeout(showElement.bind(this, true), getDelay());
}
function hideSpinner() {
//This is important. If the timer is in progress
// we need to cancel it to ensure everything stays
// in sync.
if (showTimer) {
$timeout.cancel(showTimer);
}
showTimer = null;
showElement(false);
}
function showElement(show) {
show ? elem.css({display:''}) : elem.css({display:'none'});
}
function getDelay() {
var delay = parseInt(scope.delay);
return angular.isNumber(delay) ? delay : 200;
}
}
};
}
function FakeService($timeout) {
var svc = this,
numCalls = 0;
svc.fakeCall = function(delay) {
numCalls += 1;
return $timeout(function() {
return {
callNumber: numCalls
};
}, delay || 50);
};
}
function MainCtrl(fakeService) {
var vm = this;
vm.makeCall = function(delay) {
vm.isBusy = true;
fakeService.fakeCall(delay)
.then(function(result) {
vm.result = result;
}).finally(function() {
vm.isBusy = false;
});
}
}
angular.module('spinner', [])
.service('fakeService', FakeService)
.controller('mainCtrl', MainCtrl)
.directive('spinner', SpinnerDirective);
}());
<link href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css" rel="stylesheet" />
<link href="//maxcdn.bootstrapcdn.com/font-awesome/4.2.0/css/font-awesome.min.css" rel="stylesheet">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.8/angular.min.js"></script>
<div class="container" ng-app="spinner">
<div class="row" ng-controller="mainCtrl as ctrl">
<div class="col-sm-12">
<h2>{{ctrl.result | json}}
<spinner show="ctrl.isBusy" delay="200"></spinner>
</h2>
<button type="button"
class="btn btn-primary"
ng-click="ctrl.makeCall(2000)"
ng-disabled="ctrl.isBusy">Slow Call
</button>
<button type="button"
class="btn btn-default"
ng-click="ctrl.makeCall()"
ng-disabled="ctrl.isBusy">Fast Call
</button>
</div>
</div>
</div>
Here's a simpler approach that worked for my needs. Depending on what your action is, you would tie function setDelay() to the element. For example, in my case I tied setDelay() to a select input.
Trigger HTML:
<select class="first-option"
ng-change="setDelay()"
ng-options="o.label for o in download.options"
ng-model="optionModel" required>
</select>
In your controller, add a simple function setDelay that will change the flag $scope.delay:
$scope.setDelay = function(){
$scope.delay = true;
$timeout(function(){
$scope.delay = false;
}, 200);
};
Then, you can simply use $scope.delay as a flag in ng-show:
<div class="loading-div" ng-show="delay">
<img src="loading_spinner.gif">
</div>
And show content after done loading:
<div ng-show="!delay">
Content is loaded.
</div>
Now, every time the user selects a new value in the dropdown menu, it will trigger$scope.delay to be set totrue causing the spinner to show, and when it reaches 200, it will be set to false causing the spinner to hide.
I think a pure CSS solution is the best way to do it.
Here is a plunker showing how to do it. Using ng-animate classes for transition and applying a transition delay with a transition of 10ms (0s transition is not working with css).
Relevant part of the code :
.your-element-class.ng-hide {
opacity: 0;
}
.your-element-class.ng-hide-add,
.your-element-class.ng-hide-remove {
transition: all linear 0.01s 1s;
}
The only reason to use a custom directive for it would be using this tons of times in your code with different delays value. A custom directive allow more flexibility with the delay timing.

Event driven AngularJS code, case study

Coming back from a jQuery background I find myself having a "procedural" way of seeing this when it comes ti "in-view" interactions.
The problem is, this approach leads to ALLOT of errors and the code is not maintainable.
So I have been reading on event driven JavaScript and tried to apply this concept on AngularJS.
For this, I thought about a user submitting a form, having two steps and resetting everything to an original state.
This is what I came up with: here is a plunker
1. How do you feel about this style of programming in Angular?
2. How would you optimize the code?
3. How would you do it?
Bellow is the code:
<div ng-controller="TheController" ng-init="events.init()">
<p ng-if="showName">Name: <input type="text"></p>
<p ng-if="showAge">Age: <input type="text"></p>
<p ng-if="showHeight">Height: <input type="text"></p>
<p ng-if="showWeight">Weight: <input type="text"></p>
<button ng-if="showButtonOne" ng-click="events.submittedAgeAndName()">Submit age and name</button>
<button ng-if="showButtonTwo" ng-click="events.submittedHeightAndWright()">Submit height and weight</button>
<p ng-if="showThankYou">Thank you for submitting!</p>
<button ng-if="showGetEverythingBack" ng-click="events.getEverythingBack()">Get everything back!</button>
</div>
<script type="text/javascript">
var app = angular.module('app', []);
app.controller('TheController', function ($scope) {
$scope.events = {
'init': function () {
$scope.showName = true;
$scope.showAge = true;
$scope.showHeight = false;
$scope.showWeight = false;
$scope.showThankYou = false;
$scope.showButtonOne = true;
$scope.showButtonTwo = false;
$scope.showGetEverythingBack = false;
},
'submittedAgeAndName': function () {
$scope.showName = false;
$scope.showAge = false;
$scope.showHeight = true;
$scope.showWeight = true;
$scope.showThankYou = false;
$scope.showButtonOne = false;
$scope.showButtonTwo = true;
$scope.showGetEverythingBack = false;
},
'submittedHeightAndWright': function () {
$scope.showName = false;
$scope.showAge = false;
$scope.showHeight = false;
$scope.showWeight = false;
$scope.showThankYou = true;
$scope.showButtonOne = false;
$scope.showButtonTwo = false;
$scope.showGetEverythingBack = true;
},
'getEverythingBack': function () {
this.init();
}
}
});
</script>
How do you feel about this style of programming in Angular?
Way too many pointless variables
With no purpose for all events really no function is needed, but if you do you just change the step inside like reset in the plunker.
How would you optimize the code?
Declarative html, data-binding, use directives, all the regular angular principles.
I would probably put the whole wizard in a directive, which would tuck away a lot of the template html and make the code more reusable.
How would you do it?
Here's a Plunker
<div ng-switch="events.step">
<div ng-switch-when="1"><button ng-click="events.step=2">next</button></div>
<div ng-switch-when="2"><button ng-click="events.step=3">next</button></div>
<div ng-switch-when="3"><button ng-click="events.reset();">back</button></div>
</div>

Angularjs toggle image onclick

I'm trying to toggle a button image when a user clicks it. I prefer to use angularjs instead of jquery if possible. Right now I have a working version which toggles the image when clicked, the only problem is it changes ALL the images on click. How do I reduce the scope or pass in the src attribute for the img element?
<div ng-repeat="merchant in merchants">
<div class="followrow">
<a ng-click="toggleImage()"><img id="followbutton" ng-src="{{followBtnImgUrl}}" /></a>
</div>
</div>
app.controller('FollowCtrl', function CouponCtrl($scope) {
$scope.followBtnImgUrl = '/img1'
$scope.toggleImage = function () {
if ($scope.followBtnImgUrl === '/img1.jpg') {
$scope.followBtnImgUrl = baseUrl + '/img2.jpg';
} else {
$scope.followBtnImgUrl = 'img1.jpg';
}
}
});
Can I pass in the img src attribute the function like toggleImage(this.img.src) or similar?
<div ng-repeat="merchant in merchants">
<div class="followrow">
<a ng-click="toggleImage(merchant)"><img id="followbutton" ng-src="{{merchant.imgUrl}}" />
</a>
</div>
</div>
.
app.controller('FollowCtrl', function CouponCtrl($scope) {
$scope.followBtnImgUrl = '/sth.jpg'
$scope.merchants = [{imgUrl: "img1.jpg", name:"sdf"},
{imgUrl: "img2.jpg", name: "dfsd"}];
$scope.toggleImage = function(merchant) {
if(merchant.imgUrl === $scope.followBtnImgUrl) {
merchant.imgUrl = merchant.$backupUrl;
} else {
merchant.$backupUrl = merchant.imgUrl;
merchant.imgUrl = $scope.followBtnImgUrl;
}
};
});
What you want is a new scope for each followrow. As your code stands, there's only one scope that all of the followrows are referencing.
A simple answer is to create a new controller that you attach to each followrow:
<div class="followrow" ng-controller="ImageToggleCtrl">...</div>
And then move the image toggling logic to that new controller:
app.controller('ImageToggleCtrl', function($scope) {
$scope.followBtnImgUrl = '/img1';
$scope.toggleImage = function() { /* the toggling logic */ };
});
Now, a new scope will be instantiated for each row, and the images will toggle independently.
I just added two clickable images:
<div ng-app="FormApp" ng-controller="myController" max-width="1150px;" width="1150px;" >
<input ng-show="ShowDown" type="image" style="width:250px; height:40px;" src="~/Content/Images/contactShow.png" ng-click="ShowHide()"/>
<input ng-show="ShowUp" type="image" style="width:250px; height:40px;" src="~/Content/Images/contactHide.png" ng-click="ShowHide()" />
</div>
They toggle eachothers visibility. At page load one is visible, one is not, and both clickable images call the same function:
<script type="text/javascript">
var app = angular.module('FormApp', [])
app.controller('myController', function ($scope) {
$scope.ShowDown = true;
$scope.ShowUp = false;
$scope.ShowHide = function () {
$scope.ShowDown = $scope.ShowDown ? false : true;
$scope.ShowUp = $scope.ShowUp ? false : true;
}
});
</script>

Resources