trying to colour dates in ui bootstrap calendar after ajax call - angularjs

my html code of calendar:
.appointment>button {
color: black;
background-color: red;
}
.holidays>button {
color: black;
background-color: green;
}
</style>
<uib-datepicker ng-model="dt" class="well well-sm" datepicker-options="inlineOptions" ng-change="dateSelected()" date-disabled="enableRequired(date, mode)" custom-class="colourClass(date, mode);"></uib-datepicker>
my angularjs controller code:
holidays = new Array();
var promise = servicePOST.send(appConstants.BASE_MS_URL + 'Dcrs/activityDay.php',{
"date":d
}).then(function(result) {
$scope.dcrlocked = result.dcrlocked;
$scope.leaves = result.leaves;
console.log(result.holidays);
//$scope.holidays = result.holidays;
for(i=0;i<result.holidays.length;i++)
{
holidays.push(new Date(result.holidays[i].date.replace(/-/g,',')));
}
alert(holidays.length);
return result.holidays;
});
promise.then(function(result) {
alert("holiday length after service post"+holidays.length);
$scope.colourClass = function(date, mode) {
if (mode === 'day') {
var dateToCheck = new Date(date);
for(var i = 0; i < holidays.length ; i++) {
if(areDatesEqual(holidays[i], dateToCheck)){
return 'appointment';
}
}
}
return '';
};
});
what happens now is that the colours don't get displayed! the $q is injected and the result fetched of the holidays array length is proper but now the only thing is that the colours dont get displayed! i wonder why! any help would be appreciated!

Related

Update URL in browser while scrolling a page in gatsby [duplicate]

Is it possible to change the URL in the address bar instantly when I scroll to an id? Or have a long document with multiple id and the url changes on address bar, when I hit a new id even i scroll form bottom to top.
i use Change url when manually scrolled to an anchor?
but this is not working when scroll from bottom to top.
$(function () {
var currentHash = "#";
$(document).scroll(function () {
$('.block').each(function () {
var top = window.pageYOffset;
var distance = top - $(this).offset().top;
var hash = $(this).attr('id');
// 30 is an arbitrary padding choice,
// if you want a precise check then use distance===0
if (distance < 30 && distance > -30 && currentHash != hash) {
window.location.hash = (hash);
currentHash = hash;
}
});
});
});
body {
margin: 0px;
}
div {
height: 900px;
text-align: center;
padding: 15px;
background-color: #00f;
}
div:nth-child(even) { background: #ccc; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.0/jquery.min.js"></script>
<div class="block" id="one">Block 1</div>
<div class="block" id="two">Block 2</div>
<div class="block" id="three">Block 3</div>
<div class="block" id="four">Block 4</div>
<div class="block" id="five">Block 5</div>
Thanks in advance.
After your comment, I understand what you are trying to achieve:
The following code is based on scroll up/ down.
Will store the current block and make you "jump" between blocks:
$(function () {
var blocksArr = $('.block');
var lastScrollTop = 0;
var currentBlock = 0;
$(document).scroll(function () {
var st = $(this).scrollTop();
var hash;
//make sure it is in the boundaries
if (st > lastScrollTop && currentBlock< blocksArr.length -1){
// downscroll code
hash = $(blocksArr[++currentBlock]).attr('id');
window.location.hash = (hash);
}
else
if (st < lastScrollTop && currentBlock > 0){
// scrollup code
hash = $(blocksArr[--currentBlock]).attr('id');
window.location.hash = (hash);
}
lastScrollTop = $(this).scrollTop();
});
});
"working" fiddle (hash wont change on fiddle)
added:
If you only want to see the URL changes:
$(function () {
var currentHash = "#";
var blocksArr = $('.block');
$(document).scroll(function () {
var currentTop = window.pageYOffset/1;
for (var i=0; blocksArr.length; i++){
var currentElementTop = $(blocksArr[i]).offset().top;
var hash = $(blocksArr[i]).attr('id');
if (currentElementTop < currentTop && currentTop < currentElementTop + $(blocksArr[i]).height() && currentHash!=hash){
if(history.pushState) {
history.pushState(null, null, '#'+hash);
}
else {
location.hash = '#'+hash;
}
currentHash = hash;
}
}
});
});

Can I add style and ng-style both for a single element?

I am setting style and ng-style for a single element for two different actions which is not working.
If I add both together it is not working. both are working separately
<div class="glyphicon glyphicon-heart" style="width:{{wide}}%;" ng-style="{'color': (istrue()) ? 'red' : 'yellow' }"></div>
JS
$scope.wide = 50; // dynamic value
$scope.istrue = function () {
var abc = true;
if (abc) {
return true;
}
else {
return false;
}
}
You can also apply styles byadding dynamic class name like below:
HTML
<div class="glyphicon glyphicon-heart" style="width:78%;" ng-class="isArrabic()"></div>
JS
$scope.wide = 78; // dynamic value
$scope.isArrabic = function () {
var arabic = true;
if (arabic) {
return 'floatRight';
}
else {
return 'floatLeft';
}
}
CSS:
.floatRight {
float: right;
color: red;
}
.floatLeft {
float: left;
color: blue;
}

Angular - how to make $interval work from user input

I am taking date and time from user as input and then wanted to display it interval in label
After that datetime completes I want to make that label color change.
Please guide me how can i achieve this.
https://codepen.io/shreyag020/pen/vKvmdx
$interval(function(){
todoTime=$scope.datetime;
});
Here is an example of how you could change the background color of a div over time. Clicking the start button begins a countdown timer from 1 minute. It starts out with no background, once the timer is started it turns green, at 15 seconds before time runs out it turns orange and when the time has run out it turns red. The change of the background color is animated using ng-class, ngAnimate and the animation hooks.
angular.module('app', ['ngAnimate'])
.controller('ctrl', function($scope, $interval) {
var timerPromise;
$scope.reset = function() {
$scope.userTime = new Date;
$scope.userTime.setMinutes(1);
$scope.userTime.setSeconds(0);
$scope.resetVisible = false;
$scope.started = false;
}
$scope.start = function() {
$scope.started = true;
$scope.resetVisible = false;
timerPromise = $interval(function() {
if ($scope.userTime.getSeconds() > 0 || $scope.userTime.getMinutes() > 0) {
$scope.userTime.setTime($scope.userTime.getTime() - 1000);
}
}, 1000);
}
$scope.pause = function() {
$interval.cancel(timerPromise);
$scope.started = false;
$scope.resetVisible = true;
}
$scope.timeBackground = function() {
if ($scope.started) {
if ($scope.userTime.getMinutes() === 0 && $scope.userTime.getSeconds() === 0) {
$scope.resetVisible = true;
$interval.cancel(timerPromise);
return 'expired';
}
if ($scope.userTime.getMinutes() === 0 && $scope.userTime.getSeconds() <= 15) {
return 'warning';
}
return 'ok';
}
return 'clear';
}
$scope.reset();
});
.timeDisplay {
color: white;
font-weight: bold;
}
.ok-add,
.ok-remove,
.warning-add,
.warning-remove,
.expired-add,
.expired-remove {
transition: background-color 1000ms linear;
}
.warning,
.warning-add.pre-warning-add-active {
background-color: orange;
}
.expired,
.expired-add.expired-add-active {
background-color: red;
}
.ok,
.ok-add.ok-add-active {
background-color: green;
}
.clear {
background-color: none;
color: black;
}
div {
padding: 10px;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.3/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.3/angular-animate.min.js"></script>
<div ng-app="app" ng-controller="ctrl">
<div class="timeDisplay" ng-class="timeBackground()">
Time remaining: {{userTime | date: 'mm:ss'}}
</div>
<div ng-if="!started">
<button ng-click="start()">Start</button>
</div>
<div ng-if="started">
<button ng-click="pause()">Pause</button>
</div>
<div ng-if="resetVisible">
<button ng-click="reset()">Reset</button>
</div>
</div>

create a decimal star rating for a comment in angularjs

Here is a code which present star rating code in angularjs. In some point I need to have a average of all the rating in whole the system so instead of rate:2 , i will have 2.4 . In such case i am interesting to present 2 star which are complete fill and one which has only half filled. How can I change my code in order to add this functionality?
Moreover, initially I would like to don't specify any star filled. That's also need a modification which I am not sure how should be done?
<div ng-app="app" ng-controller="RatingCtrl" class="container">
<h1>Angular Star Rating Directive</h1>
<div star-rating ng-model="rating1" max="10" on-rating-selected="rateFunction(rating)"></div>
<star-rating ng-model="rating2" readonly="isReadonly"></star-rating>
<label>
<input type="checkbox" ng-model="isReadonly" /> Is Readonly
</label>
<div><strong>Rating 1:</strong> {{rating1}}</div>
<div><strong>Rating 2:</strong> {{rating2}}</div>
</div>
In my directive
angular.module("app", [])
.controller("RatingCtrl", function($scope) {
$scope.rating1 = 1;
$scope.rating2 = 2;
$scope.isReadonly = true;
$scope.rateFunction = function(rating) {
console.log("Rating selected: " + rating);
};
})
.directive("starRating", function() {
return {
restrict : "EA",
template : "<ul class='rating' ng-class='{readonly: readonly}'>" +
" <li ng-repeat='star in stars' ng-class='star' ng-click='toggle($index)'>" +
" <i class='fa fa-star'></i>" + //&#9733
" </li>" +
"</ul>",
scope : {
ratingValue : "=ngModel",
max : "=?", //optional: default is 5
onRatingSelected : "&?",
readonly: "=?"
},
link : function(scope, elem, attrs) {
if (scope.max == undefined) { scope.max = 5; }
function updateStars() {
scope.stars = [];
for (var i = 0; i < scope.max; i++) {
scope.stars.push({
filled : i < scope.ratingValue
});
}
};
scope.toggle = function(index) {
if (scope.readonly == undefined || scope.readonly == false){
scope.ratingValue = index + 1;
scope.onRatingSelected({
rating: index + 1
});
}
};
scope.$watch("ratingValue", function(oldVal, newVal) {
if (newVal) { updateStars(); }
});
}
};
});
and css
.rating {
margin: 0;
padding: 0;
display: inline-block;
}
.rating li {
padding: 1px;
color: #ddd;
font-size: 20px;
text-shadow: .05em .05em #aaa;
list-style-type: none;
display: inline-block;
cursor: pointer;
}
.rating li.filled {
color: #fd0;
}
.rating.readonly li.filled {
color: #666;
}
http://codepen.io/anon/pen/RPLJYW
Thank you for any help.
You could use two identical set of stars to achieve this, position absolute one on top of the other. One fills your background star shapes (gray) and the one position at the top will represent your fill.
The top set of stars are all filled but its container's width can be adjusted to the proportion of stars representing your rate.
var score = 2.4;
var maxStars = 5;
var starContainerMaxWidth = 100; //pixls
var filledInStarsContainerWidth = score / maxStars * starsMaxWidth;
A CSS overflow hidden will hide the portion of stars that are not turned on, in effect allowing you to show 2.4 stars filled.
Update:
I have bashed a quick example http://codepen.io/anon/pen/NqazVa , will need some tidy up and reshuffling but the average rate is calculated and displayed correctly.
Check the AngularUI Bootstrap Rating component.
http://angular-ui.github.io/bootstrap/#/rating

Having trouble dealing with Moment JS (Angular)

I am having trouble with Moment JS. Basically, I have some metadata for a radio station, and in my php call, I get in return the 'duration' of the song, the 'timestamp' when the song started.
I did some calculation with Moment JS to get the time when the song will be finished, and then I find the difference. However, the difference is returning a negative number, which then breaks the app.
If someone can help me that would be great.
This is my plunk http://plnkr.co/edit/joVLYdTKY5dZBOTNfTOI
Services
angular.module('starter', [])
.run(function(CurrentTrack){
CurrentTrack.refreshTrackData();
})
.controller('radioCtrl', function($scope,CurrentTrack) {
console.log(CurrentTrack);
$scope.CurrentTrack = CurrentTrack;
})
.service('CurrentTrack',function(radioData,$timeout){
var currentTrack = this;
this.setTrackData = function(trackData){
currentTrack.coverUrl = trackData.cover_url;
currentTrack.title = trackData.title;
currentTrack.artist = trackData.artist;
currentTrack.duration = moment.duration(parseInt(trackData.duration));
currentTrack.startedAt = moment.unix(trackData.timestamp);
currentTrack.finishesAt = moment(this.startedAt.add(this.duration));
currentTrack.updateIn = this.finishesAt.diff(moment());
currentTrack.refreshing = false;
return currentTrack.updateIn;
}
this.refreshTrackData = function(){
currentTrack.refreshing = true;
return radioData.refresh()
.then(currentTrack.setTrackData.bind(currentTrack))
.then(currentTrack.scheduleUpdate);
}
this.scheduleUpdate = function(ms){
console.log(ms)
$timeout(function(){
currentTrack.refreshTrackData()
},ms);
return;
}
})
Factory
.factory('radioData', function($http,$timeout) {
var retries = 0;
function parseResponse(response){
retries = 0;
if(!response.data.results){
console.log('no results')
return false;
}
console.log('refreshed...')
return response.data.results[0];
}
function makeRequest(){
console.log('refreshing...')
return $http.get('http://radio-sante-animale.fr/blah11.php? callback=jsonpCallback')
}
function retry(errResponse){
console.error('timed out');
//wait for a sec
retries++;
if(retries > 5){
throw new Error('timed out after 5 attempts!');
}
//oops
return $timeout(makeRequest,1000).then(null,retry);
}
var radioData = {
refresh: function() {
return makeRequest()
.then(null,retry)
.then(parseResponse)
.catch(function(err){
console.log(err);
});
}
};
return radioData;
});
From my side, it worked by adding Math.abs in your $timeout method
this.scheduleUpdate = function(ms) {
console.log( 'update in :' + ms)
$timeout(function() {
currentTrack.refreshTrackData()
}, Math.abs(ms));
return;
}
First I changed:
currentTrack.finishesAt = moment(this.startedAt.add(this.duration));
to:
currentTrack.finishesAt = moment(currentTrack.startedAt).add(currentTrack.duration);
In the original code you are mutating the startedAt time then cloning. I also changed all the this to currentTrack to make it more consistent.
The problem
The bug manifests when there is a difference in the time the server is keeping and the time that the client is keeping, (not because you have anything reversed).
Basically the server sends you trackData.timestamp which you parse and convert into a moment to use as your startedAt time. Then you change the trackData.duration into a moment.duration and add it to the startedAt time to get your finishesAt time.
If the time that the client is keeping is running ahead the server's time, the calculated finishesAt time will be earlier than when the actual song ends. An exaggerated example makes this more clear.
var app = angular.module('app', []);
app.controller('myController', function($scope, $timeout, $interval, Server) {
function updateTime() {
$scope.serverTime = moment().subtract(1,'s');
$scope.clientTime = moment();
}
function refreshInfo() {
Server.getSongInfo().then(parseInfo).then(scheduleRefresh);
};
function parseInfo(trackData) {
$scope.songInfo = trackData;
var startedAt = trackData.timestamp;
$scope.finishesAt = moment(startedAt).add(trackData.duration, 'ms');
$scope.updateIn = $scope.finishesAt.diff(moment());
return $scope.updateIn;
}
function scheduleRefresh(updateIn) {
if (updateIn < 0) {
$scope.bugged = true;
} else {
$scope.bugged = false;
}
$timeout(refreshInfo, updateIn);
}
$scope.songInfo = "loading";
updateTime();
refreshInfo();
$interval(updateTime, 1000);
});
app.service('Server', function($timeout, $interval) {
var song = {
duration: 5000
};
this.getSongInfo = function() {
return $timeout(function() { return this.trackData });
};
function nextSong() {
this.trackData = {
duration: song.duration,
timestamp: moment().subtract(1,'s')
};
}
nextSong();
$interval(nextSong, song.duration);
});
.container {
display: flex;
flex-flow: row wrap;
}
.row {
display: flex;
flex-direction: row;
flex-flow: space-around;
width: 100%;
}
.col {
margin: auto;
text-align: center;
}
.red {
background-color: red;
}
<head>
<script data-require="angular.js#1.4.0-beta.3" data-semver="1.4.0-beta.3" src="https://code.angularjs.org/1.4.0-beta.3/angular.js"></script>
<script data-require="moment.js#2.8.3" data-semver="2.8.3" src="//cdnjs.cloudflare.com/ajax/libs/moment.js/2.8.3/moment.min.js"></script>
</head>
<div ng-app='app' ng-controller='myController'>
<div class="container">
<div class='row'>
<div class='col' ng-class='{red:bugged}'>
<h3>Song Info</h3>
<div>{{ songInfo }}</div>
</div>
</div>
<div class="row">
<div class='col'>
<h3>Server</h3>
<div>{{ serverTime.format("hh:mm:ss") }}</div>
</div>
<div class='col'>
<h3>Finishes At</h3>
<div>{{ finishesAt.format("hh:mm:ss") }}</div>
</div>
<div class='col'>
<h3>Update In</h3>
<div>{{ updateIn }}</div>
</div>
<div class='col'>
<h3>Client</h3>
<div>{{ clientTime.format("hh:mm:ss") }}</div>
</div>
</div>
</div>
</div>
Whenever the song info div is red, the client is in the loop where it is requesting new track info and parsing out a finish time that is earlier than the current moment, which immediately makes it request new track info.
angular.module('starter', [])
.run(function(CurrentTrack) {
CurrentTrack.refreshTrackData();
})
.controller('radioCtrl', function($scope, CurrentTrack) {
$scope.CurrentTrack = CurrentTrack;
})
.service('CurrentTrack', function(radioData, $timeout) {
var currentTrack = this;
this.setTrackData = function(trackData) {
currentTrack.coverUrl = trackData.cover_url;
currentTrack.title = trackData.title;
currentTrack.artist = trackData.artist;
currentTrack.duration = moment.duration(parseInt(trackData.duration));
currentTrack.startedAt = moment.unix(trackData.timestamp);
currentTrack.finishesAt = moment(currentTrack.startedAt).add(currentTrack.duration);
currentTrack.updateIn = currentTrack.finishesAt.diff(moment())
console.log(currentTrack, trackData);
currentTrack.refreshing = false;
return currentTrack.updateIn;
}
this.refreshTrackData = function() {
currentTrack.refreshing = true;
return radioData.refresh()
.then(currentTrack.setTrackData)
.then(currentTrack.scheduleUpdate);
}
this.scheduleUpdate = function(ms) {
console.log("update in " + ms)
$timeout(function() {
currentTrack.refreshTrackData()
}, ms);
return;
}
})
.factory('radioData', function($http, $timeout) {
var retries = 0;
function parseResponse(response) {
retries = 0;
if (!response.data.results) {
console.log('no results')
return false;
}
console.log('response parsed.')
return response.data.results[0];
}
function makeRequest() {
console.log('making request.')
return $http.get('http://radio-sante-animale.fr/blah11.php?callback=jsonpCallback')
}
function retry(errResponse) {
console.error('timed out');
//wait for a sec
retries++;
if (retries > 5) {
throw new Error('timed out after 5 attempts!');
}
//oops
return $timeout(makeRequest, 1000).then(parseResponse, retry);
}
var radioData = {
refresh: function() {
return makeRequest()
.then(parseResponse, retry)
.catch(function(err) {
console.log(err);
});
}
};
return radioData;
});
<!DOCTYPE html>
<html ng-app="starter">
<head>
<script data-require="angular.js#1.4.0-beta.3" data-semver="1.4.0-beta.3" src="https://code.angularjs.org/1.4.0-beta.3/angular.js"></script>
<script data-require="moment.js#2.8.3" data-semver="2.8.3" src="//cdnjs.cloudflare.com/ajax/libs/moment.js/2.8.3/moment.min.js"></script>
</head>
<body ng-controller="radioCtrl">
<h3>Current Music Information</h3>
<p ng-show="CurrentTrack.refreshing">refreshing...</p>
<img style="width:300px;height:300px;" src="{{CurrentTrack.coverUrl}}" alt="">
<p>
Title : {{ CurrentTrack.title }}
<br />Artist : {{ CurrentTrack.artist }}
<br />The song started at {{ CurrentTrack.startedAt }}
<br />Duration of the song {{ CurrentTrack.duration.asSeconds() }} seconds
<br />Finishes At {{ CurrentTrack.finishesAt }}
<br />Update In {{ CurrentTrack.updateIn }}
<br />
</body>
</html>
I'm actually not sure the best approach to fixing this problem but hopefully some one has a better answer.
A hack solution is to add more time (some acceptable amount of error) to the finishesAt to give a little leeway.
currentTrack.finishesAt = moment(currentTrack.startedAt).add(currentTrack.duration).add(1, 's');
From http://momentjs.com/docs/#/displaying/difference/
If the moment is earlier than the moment you are passing to
moment.fn.diff, the return value will be negative.
You need to reverse the dates in your diff.
EDIT: Like this -
currentTrack.updateIn = moment().diff(this.finishesAt);

Resources