Controller internal function won't update $scope variable - angularjs

I have a function inside a $scope which updates a variable inside the $scope - my problem is that the variable is being "restored" to its original value once the function ends:
function MyCtrl($scope, $http, $templateCache) {
$scope.changeWeek = function (direction) {
console.log(direction);
console.log($scope.firstdayofweek);
var d = new Date();
direction == '7' ? d.setDate($scope.firstdayofweek.getDate() + 7) : d.setDate($scope.firstdayofweek.getDate() - 7);
$scope.firstdayofweek = d;
console.log(d);
console.log($scope.firstdayofweek);
}
$scope.firstdayofweek = getMonday(new Date());
$http({ method: 'GET', url: '/TimeSheet/Services/GetSubEmployees.ashx', cache: $templateCache }).
success(function (data, status) {
$scope.status = status;
$scope.fullname = data.fullname;
$scope.accountname = data.accountname;
$scope.domain = data.domain;
$scope.subemployees = data.subemployees;
$scope.domain == 'IL' ? $scope.firstdayofweek.setDate($scope.firstdayofweek.getDate() - 1) : $scope.firstdayofweek.setDate($scope.firstdayofweek.getDate());
}).
error(function (data, status) {
$scope.data = data || "Request failed";
$scope.status = status;
});
}
The markup:
<div class="row" >
<div class="span1"></div>
<div ng-repeat="n in [] | range:7" class="span1">
{{(firstdayofweek.getDate()+$index)+'/'+(firstdayofweek.getMonth()+1)}}
</div>
<div class="span1"></div>
</div>
$scope.firstdayofweek is updated as expected inside the function (+-7 days) but {{firstdayofweek}} shows the updated date of "now" everytimg I call the function. (The console shows the right updated date)
I'm guessing the controller is refreshed every time - any way I can stop it from happening?
Thanks!

Related

Angular - Trying to access value outside of $http get success and use it for a filter value

I'm building a silly little Football app. On the first page, I am trying to load the country's top division standings and the coming week's fixtures.
I retrieve the data, using a RESTful Web Service and so is done asynchronously. The table is fine, but not the fixtures.
There is an array of fixture objects, within them, there's a 'matchday' and 'status' property. If you look at the 'this.getFixtures' function, look at the success code block. What I am trying to do is only display the fixtures for a certain match day. If there is one game left to be played on a certain matchday, then I only want that fixture displayed. If not, display next matchday's fixtures.
The 'status' property typically has a value of 'SCHEDULED' or 'FINISHED'. In the success code block I am saying:
Loop through all fixtures retrieved.
If this fixture is scheduled, that means, we're on the matchday for this fixture.
In which case, break loop.
I am then trying to use that value outside the get method, but I keep getting undefined. Is there any way to access that value outside the success block?
I'll use the $scope.matchDay function as the filter.This will help me to only display scheduled fixtures in that matchday with ng-repeat.
Anyway, sorry for the long winded post, but here's the code:
HTML:
<div class="grid-x">
<div class="medium-8 medium-offset-2 cell">
<div id="premier-league-banner">
<div class="banner-shade">
<div class="grid-x">
<div class="medium-5 cell">
<table>
<tr ng-repeat="team in premierLeagueTable.standing | limitTo: 6">
<th>{{ $index + 1 }}</th>
<td><img class="prem-thumbnail" src="{{ team.crestURI }}" /></td>
<th>{{ team.teamName }}</th>
<th>{{ team.playedGames }}</th>
<th>{{ team.goalDifference }}</th>
<th>{{ team.points }}</th>
</tr>
</table>
</div>
<div class="medium-2 cell">
<img src="images/prem-logo.png" />
</div>
<div class="medium-5 cell">
<table>
<tr ng-repeat="fixture in premierLeagueFixtures.fixtures | filter:{matchday: 10}">
<th>{{fixture.homeTeamName}}</th>
<td>vs</td>
<th>{{fixture.awayTeamName}}</th>
</tr>
</table>
</div>
</div>
</div>
</div>
</div>
Angular JS
// MODULE
var quickEleven = angular.module('quickEleven', ['ngRoute', 'ngResource']);
// ROUTES
quickEleven.config(function ($routeProvider) {
$routeProvider
.when('/', {
templateUrl: 'pages/home.htm',
controller: 'homeController'
})
});
// CONTROLLERS
quickEleven.controller('homeController', ['$scope', '$resource', '$log', 'footballData', function($scope, $resource, $log, footballData) {
function getMonday(date) {
var day = date.getDay() || 7;
if( day !== 1 )
date.setHours(-24 * (day - 1));
return date;
}
function convertDate(date) {
var yyyy = date.getFullYear().toString();
var mm = (date.getMonth()+1).toString();
var dd = date.getDate().toString();
var mmChars = mm.split('');
var ddChars = dd.split('');
return yyyy + '-' + (mmChars[1]?mm:"0"+mmChars[0]) + '-' + (ddChars[1]?dd:"0"+ddChars[0]);
}
var thisMonday = getMonday(new Date);
var nextMonday = getMonday(new Date);
nextMonday.setDate(nextMonday.getDate() + 7);
$log.info("Boom! " + convertDate(thisMonday));
$log.info("For! " + convertDate(nextMonday));
$scope.premierLeagueTable = footballData.getLeagueTable("http://api.football-data.org/v1/competitions/:competitionId/leagueTable", 445);
//http://api.football-data.org/v1/competitions/:competitionId/fixtures?timeFrameStart=2018-03-01&timeFrameEnd=2018-03-05
//"http://api.football-data.org/v1/competitions/:competitionId/fixtures/?matchday=9"
$scope.premierLeagueFixtures = footballData.getFixtures("http://api.football-data.org/v1/competitions/:competitionId/fixtures?timeFrameStart=" + convertDate(thisMonday) + "&timeFrameEnd=" + convertDate(nextMonday), 445);
$log.info($scope.premierLeagueFixtures);
$log.info($scope.premierLeagueTable);
$scope.matchdayValue = 9;
$scope.matchDay = function() {
return footballData.getMatchday();
};
}]);
quickEleven.service('footballData', ['$resource', '$log', function($resource, $log) {
//Referring to the latest matchday with the status as 'SCHEDULED'
var self = this;
var test;
self.latestScheduledMatchday = 0;
self.getMatchday = function() {
$log.info("This is: " + test);
return self.latestScheduledMatchday;
}
this.getLeagueTable = function (footballUrl, compId) {
this.footballAPI =
$resource(footballUrl, {}, {
get: {
method: "GET",
headers: {
"X-Auth-Token": "f73808b698e84dccbe4886da3ea6e755"
}
}
})
.get({
competitionId: compId
}, function(data) {
this.fussball = data;
}, function(err) {
$log.error(err);
});
return this.footballAPI;
};
this.getFixtures = function (footballUrl, compId) {
// var self;
this.footballAPI =
$resource(footballUrl, {}, {
get: {
method: "GET",
headers: {
"X-Auth-Token": "f73808b698e84dccbe4886da3ea6e755"
}
}
})
.get({
competitionId: compId
}, function(data) {
// self = data.fixtures;
self.latestScheduledMatchday = data.fixtures[0].matchday
for (var i = 0; i < data.fixtures.length; i++) {
var fixture = data.fixtures[i];
if (fixture.status == 'SCHEDULED') {
test = fixture.matchday;
break;
}
}
$log.info("Dollar signs... " + test);
}, function(err) {
$log.error(err);
});
return this.footballAPI;
};
}]);
I see 2 issues so far. One on the note of undefined values is your service might not be getting implemented correctly. AFAIK you should be returning the service in the "function($resource, $log) {" function.
Here's how I'd change it (note I've not tested this)
quickEleven.service('footballData', ['$resource', '$log', function($resource, $log) {
//Referring to the latest matchday with the status as 'SCHEDULED'
var wrappedService = {};
var test;
var latestScheduledMatchday = 0;
var getMatchday = function() {
$log.info("This is: " + test);
return latestScheduledMatchday;
}
wrappedService.getLeagueTable = function (footballUrl, compId) {
wrappedService.footballAPI =
$resource(footballUrl, {}, {
get: {
method: "GET",
headers: {
"X-Auth-Token": "f73808b698e84dccbe4886da3ea6e755"
}
}
})
.get({
competitionId: compId
}, function(data) {
wrappedService.fussball = data;
}, function(err) {
$log.error(err);
});
return wrappedService.footballAPI;
};
wrappedService.getFixtures = function (footballUrl, compId) {
wrappedService.footballAPI =
$resource(footballUrl, {}, {
get: {
method: "GET",
headers: {
"X-Auth-Token": "f73808b698e84dccbe4886da3ea6e755"
}
}
})
.get({
competitionId: compId
}, function(data) {
latestScheduledMatchday = data.fixtures[0].matchday
for (var i = 0; i < data.fixtures.length; i++) {
var fixture = data.fixtures[i];
if (fixture.status == 'SCHEDULED') {
test = fixture.matchday;
break;
}
}
$log.info("Dollar signs... " + test);
}, function(err) {
$log.error(err);
});
return wrappedService.footballAPI;
};
return wrappedService;
}]);
So instead of the function returning no service, you have your service wrapped and returned as I believe you were intending. I also removed references to "self" since your intention there (internal service variables) is more eloquently handled with var scoping in the function.
Second issue that you will see once your service is working.
$scope.premierLeagueTable = footballData.getLeagueTable("http://api.football-data.org/v1/competitions/:competitionId/leagueTable", 445);
This line does not return the request data, but returns the request object. In fact by the time $scope.premierLeagueTable is set, the request hasn't even completed yet. What you do get is access to a promise that you can put a callback function in. See the angular resource documentation for more info, specifically the third example in the user-resource section where you see .$promise https://docs.angularjs.org/api/ngResource/service/$resource#user-resource.
Whatever functionality you want to apply the data return to should live inside that .$promise.then(...) callback. I'm not entirely sure if the promise in there receives the response data, or your callback return. You'll have to read further or experiment to find that out.

angularjs ---- In the following code, I can not get the value of avatarPath

console log
angular.module('Kinder.pages.member')
.controller('MemberInfoCtrl', MemberInfoCtrl);
function MemberInfoCtrl($scope,MemberModel,Constants,fileReader,$filter,AppUtils,$http,toastr,API) {
var vm = this;
vm.member = {};
vm.member.memberType = "1";
vm.member.memberSex = "1";
vm.member.avatarPath = "";
$scope.getFile = function () {
fileReader.readAsDataUrl($scope.file, $scope);
var fileInput = document.getElementById('uploadFile').files[0];
if(!AppUtils.isUndefinedOrNull(fileInput)){
var formData=new FormData();
formData.append("picUrl",fileInput);
$http({
........
}).success(function(data, status) {
console.log(data);
if(data.stat == 'success'){
//vm will have avatarPath value in there
console.log(vm);
vm.member.avatarPath = data.path;
//vm will have avatarPath value in there
console.log(vm);
}
}).error(function(data, status) {
});
}
};
$scope.submit = function() {
//vm had loss avatarPath ...
console.log(vm.member);
};
}
I do the function is to upload pictures before the preview, upload to the server to return to the path, assigned to vm。
But I can not get the avatarPath value outside the $ scope.getFile method。
I suspect that the problem of the scope of the problem, but I can not find a solution, I am the angular novice。
So who can tell me what this is for the reason。
I used google translation to describe the above questions,
I do not know if you understand me。。。
Anyway, thank you for taking the time to browse this question!
i fix it!
thanks for #JayantPatil reminders!
i am declaring controller in the route
.state('member.info', {
url: '/info/{memberId:string}',
params: {
memberId: null
},
templateUrl: 'app/pages/member/info/member-info.html',
controller: 'MemberInfoCtrl as vm'
});
and in the html , i use the ng-controller
<div class="userpic" ng-controller="MemberInfoCtrl as vm">
<input type="file" ng-show="false" id="uploadFile" ng-file-select/>
</div>
cause i duplicate declarations the controller , maybe the Scopes is Different,
that is all

Angular ng-repeat custom filter giving unresolved variable

Im trying to complete this custom filter to filter a list of all "savings" created in the last 24 hours
Controller filter
angular.module('savings').filter('lessThan', function () {
return function(savings, requirement) {
var filterKey = Object.keys(requirement)[0];
var filterVal = requirement[filterKey];
var filtered = [];
if(filterVal !== undefined && filterVal !== ''){
angular.forEach(savings, function(saving) {
var today = new Date();
var date = new Date(saving.created.$date); <-- Unresolved variable $date
alert(date);
var diff = today - date;
diff = diff / (1000*60*60);
if(diff < filterVal) {
filtered.push(saving);
}
});
return filtered;
}
return savings;
};
});
And here is how i call it from the view
<div ng-repeat="saving in savings | orderBy: '-votesreal' | limitTo:6 | lessThan: {'created.$date':24}" class="col-lg-2 no-padding-spotlight text-center">
<div class=" thumbnail-spotlight thumbnail centred-image">
<img src="{{saving.image}}" /><br>
<a class="text-center" ng-href="/savings/{{saving._id}}" ng-bind="saving.title +' (€'+ saving.price +' # '+ saving.retailer+')'"></a>
</div>
</div>
Ive wrote a note where the unresolved variable is. How do i declare the "saving" object which is coming from the database. Without the filter it returns all results fine.
Controller Code
angular.module('savings').controller('SavingsController', ['$scope', '$timeout', '$stateParams', '$location', '$window', 'Authentication', 'Savings', 'FileUploader',
function($scope, $timeout, $stateParams, $location, $window, Authentication, Savings, FileUploader) {
$scope.authentication = Authentication;
$scope.user = Authentication.user;
$scope.savingImageURL = '/modules/users/client/img/profile/saveme-placeholder.png';
// $scope.user.imageURL = '/modules/users/client/img/profile/saveme-placeholder.png';
$scope.imageURL1 = '';
$scope.hottestsorted = true;
$scope.newestsorted = true;
$scope.brandLogo = '/modules/users/client/img/profile/argos-logo.png';
$scope.spotlightSort = Savings.votesreal;
$scope.savings = Savings;
//$scope.user.imageURL = '';
$scope.submitFormSaving = function(isValid) {
$scope.submitted = true;
};
}
]);
Client.service
//Savings service used for communicating with the savings REST endpoints
angular.module('savings').factory('Savings', ['$resource',
function ($resource) {
return $resource('api/savings/:savingId', {
savingId: '#_id'
}, {
update: {
method: 'PUT'
}
});
}
]);
Well it's good to see that $scope.savings has snuck in there. Try something like this:
Instead of $scope.savings = Savings; use:
Savings.query({}, function(resp){
console.log(resp);
$scope.savings = resp;
});
If your api endpoint needs the savingId use:
Savings.query({ savingId: [something] }, function(resp){
console.log(resp);
$scope.savings = resp;
});
This should work for you.

AngularJS Count Yes/No Values

I'm currently working on a AngularJS / Parse.com web application
What I'm trying to achieve:
I would like to get the total amount of Yes & No values within an Array.
e.g Yes = 3 No = 6
Current Problems:
I've managed to get all Yes & No values from Parse and put them into an Array but I'm unable to count the amount of Yes or No values.
Any help / advice would be helpful!
HTML:
<md-card>
<md-card-content>
<canvas id="doughnut" class="chart chart-doughnut" data="widgetone_data" labels="widgetone_label"></canvas>
</md-card-content>
{{widgetone_data | json}}
</md-card>
Controller JS:
dashApp.controller("dashboardCtrl", function ($scope, $http, $filter) {
$scope.parseRecommendations = [];
$http({
method : 'GET',url : 'https://api.parse.com/1/classes/Customers',
headers: { 'X-Parse-Application-Id':'xxx', 'X-Parse-REST-API-Key':'xxx'}
})
.success(function(data, error) {
$scope.parseResults = data.results;
angular.forEach($scope.parseResults, function(results) {
$scope.parseRecommendations.push(results.question_4_p1);
});
})
.error(function(data, error) {alert('Failed, error code: ' + error.message);
});
// Recommend YES/NO
var yesAmount = $filter('filter')($scope.parseRecommendations, { isSelected: 'yes' }).length;
var noAmount = $filter('filter')($scope.parseRecommendations, { isSelected: 'no' }).length;
$scope.widgetone_label = ["Yes", "No"];
$scope.widgetone_data = [yesAmount,noAmount];
});
You can use the .filter() method.
Moreover, you made an error, because you start to filter your data when the controller is instantiated, but your API call is asynchronous, so you have to filter your data into the .success() callback, otherwise you will filter an empty array.
EDIT : To improve performance, you can count your by simulating an hashmap. See below
dashApp.controller("dashboardCtrl", function ($scope, $http, $filter) {
$scope.parseRecommendations = [];
var hashmap = {};
$http({
method : 'GET',url : 'https://api.parse.com/1/classes/Customers',
headers: { 'X-Parse-Application-Id':'wmWxU64vx0QgKBiNQkx9jCDNO6UZDRrM6WkxAbTL', 'X-Parse-REST-API-Key':'0FHcBHZdeUJHKT8j0VQH0hQdN4TZ8qsOBxyd1rG3'}
})
.success(function(data, error) {
$scope.parseResults = data.results;
angular.forEach($scope.parseResults, function(results) {
$scope.parseRecommendations.push(results.question_4_p1);
});
$scope.parseRecommendations.forEach(function(elm){
hashmap.hasOwnProperty(elm)
? ++hashmap[elm]
: hashmap[elm] = 1
});
//Filter yes
var yesAmount = hashmap.yes;
//Filter no
var noAmount = hashmap.no;
$scope.widgetone_label = ["Yes", "No"];
$scope.widgetone_data = [yesAmount,noAmount];
console.log($scope.widgetone_data);
})
.error(function(data, error) {alert('Failed, error code: ' + error.message);
});
});

AngularJS: model data from http call not available in directive

There seems to be a bug where model data fetched from an http call is present in the $scope but not in a directive. Here is the code that illustrates the problem:
Jsfiddle: http://jsfiddle.net/supercobra/hrgpc/
var myApp = angular.module('myApp', []).directive('prettyTag', function($interpolate) {
return {
restrict: 'E',
link: function(scope, element, attrs) {
var text = element.text();
//var text = attrs.ngModel;
var e = $interpolate(text)(scope);
var htmlText = "<b>" + e + "</b>";
element.html(htmlText);
}
};
});
function MyCtrl($scope, $http, $templateCache) {
$scope.method = 'JSONP';
$scope.url = 'http://angularjs.org/greet.php?callback=JSON_CALLBACK&name=Super%20Hero';
$scope.fetch = function () {
$scope.code = null;
$scope.response = null;
$http({
method: $scope.method,
url: $scope.url,
cache: $templateCache
}).
success(function (data, status) {
$scope.status = status;
$scope.data = data;
}).
error(function (data, status) {
$scope.data = data || "Request failed";
$scope.status = status;
});
};
}
The HTML
<div ng-controller="MyCtrl">
<h1>Angular $http call / directive bug</h1>
<p>This fiddle illustrates a bug that shows that model w/ data fetched via an http call
is not present within a directive.</p>
<hr>
<h2>HTTP call settings</h2>
<li>Method: {{method}}
<li>URL: {{url}}
<br>
<button ng-click="fetch()">fetch</button>
<hr/>
<h3>HTTP call result</h3>
<li>HTTP response status: {{status}}</li>
<li>HTTP response data: {{data}}</li>
<hr/>
<h2>Pretty tag</h2>
<pretty-tag>make this pretty</pretty-tag>
<hr/>
<h3 style="color: red" >Should show http response data within pretty tag</h3>
[<pretty-tag>{{data}}</pretty-tag>] // <=== this is empty
</div>
Jsfiddle: http://jsfiddle.net/supercobra/hrgpc/
Any help appreciated.
You are replacing the content of the directive in your directive implementation. Since the $http request is async, the directive completes before the data is retrieve and assigned to the scope.
Put a watch on data variable inside the directive and then re-render the content, something like
scope.$watch(attrs.source,function(value) {
var e = $interpolate(text)(scope);
var htmlText = "<b>" + e + "</b>";
element.html(htmlText);
});
Based on #Marks feedback and your request i have update fiddle
http://jsfiddle.net/cmyworld/V6sDs/1/

Resources