angularJS using service variable - javascript

I need to call the service variable in controller.
I tried to call $scope.userData1.data.name outside the Service function , it is undefined.
If I put {{userData1}} in template Messages Ctrl , it shows up all the data array including names.
I need to load the i-frame using the user_name variable.
angular.module('starter.controllers', [])
.factory('UserService', function($http) {
var data;
return{
getData: function($http) {
return $http.get("http://www.website.com/index.php/id/user/call12").
success(function(response) {
/// console.log(JSON.stringify(response));
userData=response.data;
return userData;
}).error(function(data, status, headers, config) {
// log error
});
}
}
})
.controller('MessagesCtrl',function ($scope, Messages,$http,$ionicPopup,$timeout,$window,UserService,Outbox,$sce) {
$scope.userData1 = {}; // updated
$scope.myCtrl2= function(UserService,$http) {
UserService.getData($http).then(function(data) {
$scope.userData1 = data;
console.log($scope.userData1.data.name); // USERNAME exist
var name= $scope.userData1.data.name;
});
}
$scope.myCtrl2(UserService,$http);
var name= $scope.userData1.data.name; //undefined
$scope.formData4.upload_url = $sce.trustAsResourceUrl("http://www.website.com/index.php/id/user/view_form/"+ name);
})
template :
<form ng-controller="MessagesCtrl" ng-disabled="isRequesting">
<span class="item item-input" >
<span class="input-label"> </span>
<iframe id="iframe-123" src="{{formData4.upload_url}}" style="border: 0px none; height: 80px; margin: auto; width: 100%; overflow: hidden;" frameborder=0></iframe></span>
</form>

You got undefined because at this point, the answer (http.get) not yet return from the server.
You have to ensure this function $scope.myCtrl2(UserService,$http) received the answer asynchronous before you can call to the next line (var name= $scope.userData1.data.name;).
The best solution is to use promise - $q service like this:
.controller('MessagesCtrl',function ($scope, Messages,$http,$ionicPopup,$timeout,$window,UserService,Outbox,$sce,$q) {
$scope.userData1 = {}; // updated
$scope.myCtrl2= function(UserService, $http)
{
var deferred = $q.defer();
UserService.getData($http).then(function(data)
{
$scope.userData1 = data;
console.log($scope.userData1.data.name); // USERNAME exist
var name= $scope.userData1.data.name;
deferred.resolve();
});
return deferred.promise;
}
$scope.myCtrl2(UserService,$http).then(function(){
var name= $scope.userData1.data.name; //Now you got the answer!!!
$scope.formData4.upload_url = $sce.trustAsResourceUrl("http://www.website.com/index.php/id/user/view_form/"+ name);
});
})

Related

AngularJS: basic error-handling

I would like to reflect post request status by showing/hiding success/error html element with the error description. I have following controller with use of $http service:
$ctrl.addCorporateTransport = function() {
var postStatusBar = angular.element('postStatusBar');
$http.post('/post_corporate_transport', $ctrl.corporateTransport)
.success(function () {
// throw success alert
})
.error(function (error) {
// throw error alert
});
};
I'm looking for having possibility to throw <div class="alert"><p>my error here</p> if I hit error callback.
I tried this:
var statusBar = angular.element('postStatusBar');
//...
.success(function () {
statusBar.setClass("alert-success")
})
.error(function (error) {
statusBar.setClass("alert-danger");
statusBar.setParameter("text", error);
});
But it doesn't work obviously and looks like anti-pattern. What is the best solution for doing the thing?
If the alert component is outside controller scope than you need make the alert a directive and use broadcast to notify and update properties like visibility.
else you can bind properties from controller like:
<div ng-controller="AwesomeController as AwesomeCtrl">
<div class="alert" ng-show="AwesomeCtrl.show.error">....
<div class="alert" ng-show="AwesomeCtrl.show.success">....
<div class="alert" ng-class="{ 'succes' : AwesomeCtrl.show.success }">....
enter code here
angular
.module('app')
.controller('AwesomeController', controller);
controller.$inject = ['$http'];
function controller($http) {
var vm = this;
vm.corporateTransport = {};
vm.show = {
error = false;
success = false;
}
vm.oneCoolMethod = addCorporateTransport;
// test
addCorporateTransport();
function addCorporateTransport() {
$http.post('/post_corporate_transport', vm.corporateTransport)
.success(onTransportSuccess)
.error(onTransportError);
};
function onTransportSuccess(result) {
toggleAlert('success');
}
function onTransportError(result) {
toggleAlert('error');
}
function toggleAlert(level) {
angular.forEach(vm.show, function(value, key) {
vm.show[key] = false;
});
vm.show[level] = true;
}
at the first you must using $scope.statusBar
and also addClass except setClass

Call function in angular controller after clickin on a dynamiclly created element in DOM

Hi I want to call a function after clicking on a button which is added to dom after angular is loaded. I dont know if this is possible in the way I am trying it, but I do know that my current code doesn't call the alert function.
After sending a search request to my backend, I get a list data entrys, which I display as hrefs.
my_form.setAttribute("href", result[i].url)
my_form.setAttribute("ng-href",'#here')
my_form.setAttribute("ng-click", "alert(1)")
my_form.setAttribute("style", "display:block;")
results in
John Doe
Complete Code:
var appModule = angular.module('graph', [])
appModule.controller('graphCtrl', ['$scope', '$http', '$compile', function ($scope, $http, $compile) {
$scope.search = function () {
var data = {
}
$http.get('/api/search/?q=' + $scope.searchfield, data).success(function (data, status, headers, config) {
var result = data;
var searchResultsContainer = document.getElementById("dropdownId");
while (searchResultsContainer.firstChild) {
searchResultsContainer.removeChild(searchResultsContainer.firstChild);
}
for (i in result) {
var my_form = document.createElement("a");
my_form.setAttribute("href", result[i].url)
my_form.setAttribute("ng-href",'#here')
my_form.setAttribute("ng-click", "alert(1)")
my_form.setAttribute("style", "display:block;")
my_text = document.createTextNode(result[i].caption)
my_form.appendChild(my_text)
searchResultsContainer.appendChild(my_form)
}
})
}
$scope.alert = function(){
alert("Hello! I am an alert box!!");
}
}

Angular infinite scroll adding broken directive templates every time it gets new data

I am working on a social feed that displays charitable activities. It's supposed to look like the second activity in this image:
But as you can see, every time that angular-infinite-scroll goes to fetch the next batch of activities, it adds a broken template to the top of the feed.
This is the function that's called to get more activities:
feedService.prototype.nextPage = function () {
var fs = this;
if (fs.busy) return;
fs.busy = true;
fs.params.limit = fs.params.limit || _feedLimit;
if (fs.activities.length > 0)
fs.params.idLessThan = fs.activities[fs.activities.length - 1].id;
$http({ url: serviceBase + 'api/stream/getflatfeed', method: 'GET', params: fs.params })
.then(function (response) {
var feed = response.data;
console.dir(feed.results);
console.dir(fs.activities);
if (feed) {
fs.duration = feed.duration;
fs.gStreamMessage = feed.gStreamMessage;
fs.unread = feed.unread;
fs.unseen = feed.unseen;
fs.noMoreActivity = false;
if (response.data.results && response.data.results.length === 0)
fs.noMoreActivity = true;
else {
var acts = _decorateFeedActivities(response.data.results, fs.params);
acts.forEach(function (act) {
var alreadyExists = false;
fs.activities.forEach(function (e, i) {
if (e.id === act.id) {
console.log('alreadyExists!');
alreadyExists = true;
}
});
if (!alreadyExists) {
fs.activities.push(act);
}
});
};
}
fs.busy = false;
}.bind(this));
};
This is the directive used for activities:
feedModule.directive('feedCard', ['$compile', '$http', '$filter', function ($compile, $http, $filter) {
var getTemplate = function (contentType) {
var templateLoader,
baseUrl = 'app/areas/feed/cards/',
templateMap = {
donated: 'general-donation-card-tpl.html',
image: 'image-card-tpl.html',
video: 'video-card-tpl.html',
quote: 'quote-card-tpl.html',
link: 'link.html',
chat: 'chat.html',
audio: 'audio.html',
answer: 'answer.html'
};
var templateUrl = baseUrl + templateMap[contentType];
templateLoader = $http.get(templateUrl);
return templateLoader;
};
return {
restrict: 'E',
scope: {
activity: '=',
user: '='
},
replace: true,
link: linker
};
function linker(scope, element) {
var loader = getTemplate(scope.activity.verb);
var promise = loader.success(function (html) {
element.html(html);
}).then(function (response) {
element.replaceWith($compile(element.html())(scope));
console.log('---------------');
});
}
}]);
And this is the HTML for the infinite-scroll directive and the activities within:
<div class="infinite-scroll" infinite-scroll='feed.nextPage()' infinite-scroll-disabled='feed.busy || feed.noMoreActivity'>
<feed-card class="portlet light bordered feed-card message-card" ng-repeat="activity in feed.activities" activity="activity" user="data.user"></feed-card>
<div class="well" ng-show='feed.busy'>Loading data...</div>
<div class="well" ng-show='feed.noMoreActivity'>There is no more activity on your feed...</div>
</div>
I'm at a loss for what's happening. The additional, broken activities don't appear in any arrays of API returns. I would assume that it's maybe some sort of scoping issue that would cause the directive to fire twice, with one of them being broken?
If anyone has experienced anything like this, I would love to hear your advice. Thank you.
Fixed this by adding "ng-if='activity'" to the feed-card element.

Angular js multiple controller on single page with $this

I have two controllers on single page. For some reason only one of them works at a time. That is if I comment the lower div. Then upper one works and vice-versa.
index.html
<div ng-controller="MessageController as ctrl">
{{ctrl.messages}}
</div>
<div ng-controller="CommentController as ctrl">
{{ctrl.comments}}
</div>
app.js
var app = angular.module('plunker', []);
var prefix = 'http://jsonplaceholder.typicode.com';
app.controller('MessageController', ['$http', function ($http) {
$this = this;
$http.get(prefix + '/posts/1').success(function (response) {
$this.messages = response;
return response;
});
}]);
app.controller('CommentController', ['$http', '$scope', function ($http) {
$this = this;
$http.get(prefix + '/posts/2').success(function (response) {
$this.comments = response;
return response;
});
}]);
Here's plucker http://plnkr.co/edit/BXzj9GeP88BQeIA3UTWN?p=preview
You're issue is that $this is leaking onto the global scope. If you prefix the declaration with the var keyword it will reside on each controller constructors lexical scope.
app.controller('CommentController', ['$http', '$scope', function ($http) {
var $this = this;
$http.get(prefix + '/posts/2').success(function (response) {
$this.comments = response;
return response;
});
}]);

Angularjs - hide div with "if" and "else"

I would only like to show a div when user is logged in and on their profile but disabled when logged off and on another users profile.
I attempted to do this below but was unsuccessful. I would like to know what is the best possible way of going about this?
Service.js
(function () {
'use strict';
angular
.module('app.authentication.services')
.factory('Authentication', Authentication);
Authentication.$inject = ['$cookies', '$http'];
function Authentication($cookies, $http) {
var Authentication = {
getAuthenticatedAccount: getAuthenticatedAccount,
isAuthenticated: isAuthenticated
};
return Authentication;
function getAuthenticatedAccount() {
if(!$cookies.authenticatedAccount) {
return;
}
return JSON.parse($cookies.authenticatedAccount);
}
function isAuthenticated() {
return !!$cookies.authenticatedAccount;
}
})();
Controller.js
(function () {
'use strict';
angular
.module('app.profiles.controllers')
.controller('ProfileController', ProfileController);
ProfileController.$inject = ['$location', '$routeParams', 'Posts', 'Profile', 'Snackbar'];
function ProfileController($location, $routeParams, Posts, Profile, Authentication, Snackbar) {
var vm = this;
activate();
function activate() {
var authenticatedAccount = Authentication.getAuthenticatedAccount();
var username = $routeParams.username.substr(1);
// This will show Cog settings button
// when user is logged in and on their profile,
// but hidden when logged off and also when on
// another users profile
if (!authenticatedAccount) {
vm.profileCog = false;
// console.log('User not logged in');
}
else {
if(authenticatedAccount.username !== username) {
vm.profileCog = false;
// console.log('Not logged in user');
}
else {
vm.profileCog = true;
//console.log('logged in user');
}
}
}
})();
profile.html
<div ng-controller="ProfileCogController">
<div ng-show="!profileCog"></div>
</div>
According to your comment that getAuthenticatedAccount is always asynchronous:
This means you'll need to either A) explicitly watch it, or B) evaluate it once it completes. Something like this:
function activate() {
Authentication.getAuthenticatedAccount().then(function(account) {
var username = $routeParams.username.substr(1);
if(!account || account.username !== username) {
vm.profileCog = false;
}
});
// rest of code omitted
You'll need to make sure that Authentication.getAuthenticatedAccount returns a promise for this to work (by default, async calls using AngularJS internal libraries should always return a promise, aka, something that is thenable).
Solved:
controller.js
(function () {
'use strict';
angular
.module('resonanceinn.profiles.controllers')
.controller('ProfileCogController', ProfileCogController);
ProfileCogController.$inject = ['Authentication', '$routeParams', 'Profile'];
function ProfileCogController(Authentication, $routeParams, Profile) {
var vm = this;
vm.profileCog = false;
activate();
function activate() {
var authenticatedAccount = Authentication.getAuthenticatedAccount();
var username = $routeParams.username.substr(1);
if (!authenticatedAccount) {
vm.profileCog = false;
// console.log('User not logged in');
}
else {
if(authenticatedAccount.username !== username) {
vm.profileCog = false;
// console.log('Not logged in user');
} else {
vm.profileCog = true;
// console.log('logged in user');
}
}
}
}
})();
profile.html
<div ng-controller="ProfileCogController">
<div ng-show="vm.profileCog"></div>
</div>
you need to specify the controller and app name in your html file:
1) specify the controller and app name in any parent tag of current div tag if any
2) otherwise, specify the same with in the same div tag
Like:
angular.module('showApp', [])
.controller('mainController', function($scope) {
$scope.isvisible=false;
$scope.showDiv=function()
{
if(!$scope.isvisible)
$scope.isvisible=true
else
$scope.isvisible=false
}
});
<!doctype html>
<html lang="en" >
<head>
<meta charset="UTF-8">
<title>Example</title>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.4.4/angular.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.4.4/angular-animate.js"></script>
</head>
<body ng-app="showApp" ng-controller="mainController">
Show me: <input type="checkbox" ng-click="showDiv()" ><br/>
<div ng-show="isvisible">I show up when your checkbox is checked.
</div>
</body>
</html>
Thanks,

Categories

Resources