I'm trying to build real time service messaging with MongoDB and AngularJS. For some reason, when there is new data in my 'messaging' collection, the Messaging.getAllMessages() service is not triggered and my data is not updated in the view, using $watchCollection.
This is in my services.js, the important function is getAllMessages():
angular.module('myApp')
.factory('Messaging', function($resource, $http, $q, $rootScope){
var myData = {};
return {
sendMessage: function(message, success, error) {
$http.post('/api/v1/users/' + message.to.id + '/messages', message).success(function(res) {
toastr.success('Message sent');
}).error(function(error) {
toastr.error("Error on save");
});
},
getAllMessages: function(userId) {
var deferred = $q.defer();
if(!myData) {
deferred.resolve(myData);
} else if (userId && userId !== '') {
$http.get('/api/v1/users/' + userId+ '/messages').success(function(data) {
myData = data;
deferred.resolve(myData);
// update angular's scopes
$rootScope.$$phase || $rootScope.$apply();
});
} else {
deferred.reject();
}
return deferred.promise;
},
markAsRead: function(ids, success, error) {
var deferred = $q.defer();
if(!myData) {
deferred.resolve(myData);
} else if (ids && ids !== '') {
$http.put('/api/v1/users/' + ids.userId + '/messages/' + ids.messageId).success(function(data) {
myData = data;
deferred.resolve(myData);
// update angular's scopes
$rootScope.$$phase || $rootScope.$apply();
});
} else {
deferred.reject();
}
return deferred.promise;
},
getMessage: function(ids, success, error) {
return $http.get('/api/v1/users/' + ids.userId + '/messages/' + ids.messageId);
},
deleteMessage: function(ids, success, error) {
return $http.delete('/api/v1/users/' + ids.userId + '/messages/' + ids.messageId);
}
}
});
This is in directive.js:
angular.module('myApp').directive('messaging', ['$log', 'Messaging', function($log, Messaging){
return {
scope: true,
restrict: 'A', // E = Element, A = Attribute, C = Class, M = Comment
templateUrl: '/views/templates/messaging-dropdown.html',
replace: true,
link: function($scope, iElm, iAttrs, controller) {
Messaging.getAllMessages($scope.user.id).then(function(myData) {
$scope.allMessages = myData;
$scope.newMessages = 0;
$scope.$watchCollection('allMessages', function(newVal, oldVal){
if(newVal !== oldVal) {
$scope.newMessages = 0;
// Count the number of unread messages
for (var i = myData.length - 1; i >= 0; i--) {
if(myData[i].read === false) {
$scope.newMessages++;
}
};
}
}, true);
}, function() {
// request failed (same as 'return false')
$scope.allMessages = 'i got the error';
});
}
};
}]);
And this is the template, messaging-dropdown.html:
<div>
<a ng-click="showMessages()" ng-class="{clicked: messagesToggled}">
<i class="fa fa-envelope"></i>
<span class="badge" ng-show="newMessages > 0">{{newMessages}}</span>
</a>
<ul class="dropdown-menu" ng-show="messagesToggled">
<li ng-repeat="message in allMessages | limitTo: 5 | orderBy:'sent'">
<a ng-href="/users/{{message.to.id}}/messages/{{message._id}}" ng-class="{unread: !message.read}">
<img ng-src="{{message.from.image}}" alt="" class="img-circle">
<span class="body">
<span class="from">{{message.from.name}}</span>
<span class="message">
{{message.text}}
</span>
<span class="time">
<span>{{message.sent}}</span>
</span>
</span>
</a>
</li>
<li class="footer">
<a ng-href="/users/{{user.id}}/messages">See all <b>{{allMessages.length}}</b> messages</a>
</li>
</div>
As you see the $scope.newMessages is not updated by the watch, when there is new data in the array returned by the serive. I'm missing something, is there need for socket.io or Pusher/Pubnub to achieve the desired behaviour? Thanks in advance for any help.
Thanks #Sunil for pointing that out. I originally thought, that $watch() and $watchCollection(), will pull automatically and check the service for new data based on specific interval provided by the $digest() cycle.
I released that my solution needs some kind of trigger, so that the new data to be pulled from the service when available. So I implemented private messaging channels using socket.io for triggering updates on message sent from the other party.
Here is the updated directive:
Updated directive.js:
angular.module('myApp').directive('messaging', ['$log', 'Messaging', 'messagingSocket', function($log, Messaging, messagingSocket){
// Runs during compile
return {
scope: true,
restrict: 'A', // E = Element, A = Attribute, C = Class, M = Comment
templateUrl: '/views/templates/messaging-dropdown.html',
replace: true,
link: function($scope, iElm, iAttrs, controller) {
messagingSocket.emit('setUser', {id: $scope.user.id});
$scope.allMessages = function(){
Messaging.getAllMessages($scope.user.id).then(function(myData) {
$scope.allMessages.messages = myData;
}, function() {
// request failed (same as your 'return false')
$scope.allMessages = 'i got the error';
});
};
$scope.allMessages();
messagingSocket.forward('new message', $scope);
$scope.$on('socket:new message', function (event, data) {
$scope.allMessages();
});
$scope.$watchCollection('allMessages.messages', function(newVal, oldVal){
if(newVal !== oldVal) {
$scope.newMessages = 0;
// Count the number of unread messages
for (var i = $scope.allMessages.messages.length - 1; i >= 0; i--) {
if($scope.allMessages.messages[i].read === false) {
$scope.newMessages++;
}
};
}
}, true);
}
};
}]);
Related
I am pretty new to ionic and working on an app where you load a bunch of categories ,followed by a list of items in the category and when you click on the item in the category a documenturl loads containing the content which is basically an image. Currently, everything loads fine, but I would like to preload the content the moment my category is visible, so even if I go offline I should be able to click on any of the items within the category list and load the respective document. I looked online but I couldn't find anything except localstorage which caches data after you have visited it and not before. Is there a way I can pre-load or pre-cache content ?
Here's my code for controllers:
angular.module('starter.controllers', ["utility.services"])
.directive("bindCompiledHtml", ["$compile", "zoomPerOrientation", function($compile, zoomPerOrientation) {
return {
template: '<div></div>',
scope: {
rawHtml: '=bindCompiledHtml'
},
link: function(scope, elem, attrs) {
scope.$watch('rawHtml', function(value) {
if (!value) return;
var newElem = $compile(value)(scope.$parent);
elem.contents().remove();
zoomPerOrientation.zoomTo('docScroll');
elem.append(newElem);
elem.bind("click", function(e) {
e.stopPropagation();
e.preventDefault();
if (e.target.tagName === 'A') {
window.open(encodeURI(e.target.href), '_system', "presentationstyle=fullscreen,closebuttoncaption=close,location=no,transitionstyle=fliphorizontal");
return false;
} else if (e.target.parentNode.tagName === 'A') {
window.open(encodeURI(e.target.parentNode.href), '_system', "presentationstyle=fullscreen,closebuttoncaption=close,location=no,transitionstyle=fliphorizontal");
return false;
}
});
});
}
};
}])
.directive('setHeight', function($window) {
return {
link: function(scope, element, attrs) {
element.css('height', $window.innerHeight + 30);
}
}
})
.controller("MenuCtrl", ["$scope", "MenuService", "$stateParams", "$state", "ConfigUrls", function($scope, MenuService, $stateParams, $state, ConfigUrls) {
// debugger;
console.log("MenuCtrl");
$scope.menuData = [];
$scope.noMenuDataMsg = "Loading....";
$scope.LoadMenu = function(forceLoad) {
console.log("MenuCtrl - LoadMenu");
// console.log(MenuService.getClinicalAreas(forceLoad));
MenuService.getClinicalAreas(forceLoad).then(function(data) {
$scope.menuData = data;
}, function(err) {
console.log(err);
if (err.error === "timeout") {
$scope.noMenuDataMsg = "Error: Unable to retrieve data due to network error! Please try again when you are in network."
} else {
$scope.noMenuDataMsg = "Error retrieving data! Please contact system administrator."
}
$scope.menuData = [];
}).finally(function() {
$scope.$broadcast('scroll.refreshComplete');
});
}
$scope.deviceModel = window.localStorage.getItem("deviceModel");
// console.log(MenuService);
// console.log($scope.menuData);
$scope.title = $stateParams.topTitle;
var metaTag = $stateParams.metaTag;
//console.log(ConfigUrls[metaTag+"Published"]);
if (metaTag !== "") {
window.localStorage.setItem('publishedUrl', ConfigUrls[metaTag + "Published"]);
window.localStorage.setItem('docUrl', ConfigUrls[metaTag + "DocUrl"]);
window.localStorage.setItem('cacheKeyPrefix', metaTag);
$scope.LoadMenu(false);
} else {
$scope.noMenuDataMsg = "Under Construction!";
}
//console.log("metaTag",metaTag);
//if ($stateParams.topTitle === "Transplant") {
// $scope.LoadMenu(false);
//}
//else {
// $scope.noMenuDataMsg = "Under Construction!";
//}
$scope.showHomeItem = function(clinicalArea) {
console.log("MenuCtrl - showHomeItem");
$state.go('contr.home', {
cA: clinicalArea
});
}
$scope.goHome = function() {
console.log("MenuCtrl - goHome");
$state.go('contr.topmenu');
}
}])
.controller("HomeCtrl", ["$scope", "HomeService", "$stateParams", "$state", function($scope, HomeService, $stateParams, $state) {
console.log("HomeCtrl");
$scope.organs = [];
$scope.title = $stateParams.cA;
$scope.LoadHome = function(forceLoad) {
console.log("HomeCtrl - LoadHome");
HomeService.getOrgans($stateParams.cA, forceLoad).then(function(data) {
$scope.organs = data;
}, function(err) {
$scope.organs = [];
}).finally(function() {
$scope.$broadcast('scroll.refreshComplete');
});
}
$scope.showLevel2Item = function(title, clinicalArea) {
console.log("HomeCtrl - showLevel2Item");
$state.go('contr.level2', {
title: title,
cA: clinicalArea
});
//:title/:cA
}
$scope.goHome = function() {
console.log("HomeCtrl - goHome");
$state.go('contr.topmenu');
}
$scope.LoadHome(false);
}])
.controller('Level2Ctrl', ["$scope", "OrganService", "$stateParams", "$state", function($scope, OrganService, $stateParams, $state) {
$scope.title = "Level2 ";
console.log("Level2Ctrl");
$scope.parentOrgan = {};
$scope.viewTitle = $stateParams.title;
OrganService.getSingleOrganDetail($stateParams.cA, $stateParams.title).then(function(data) {
$scope.parentOrgan = data[0];
$scope.parentOrgan.clinicalAreaDisp = "Transplant";
}, function(err) {
$scope.parentOrgan = {};
});
console.log($scope.parentOrgan);
$scope.subGroup = [];
$scope.LoadSubGroups = function(forceLoad) {
console.log("Level2Ctrl - LoadSubGroups");
OrganService.getSubGroups($stateParams.title, $stateParams.cA, forceLoad).then(function(data) {
$scope.subGroup = data;
console.log("$scope.subGroup", $scope.subGroup);
}, function(err) {
$scope.subGroup = [];
}).finally(function() {
$scope.$broadcast('scroll.refreshComplete');
});
}
//$scope.deviceModel = window.localStorage.getItem("deviceModel");
//$scope.devicePlatform = window.localStorage.getItem("devicePlatform");
$scope.toggleGroup = function(group) {
group.show = !group.show;
};
$scope.isGroupShown = function(group) {
return group.show;
};
$scope.showDocumentDtl = function(id, docTitle, sgName, mnGroup, area) {
console.log("Level2Ctrl - showDocumentDtl");
$state.go('contr.doc-dtl', {
id: id,
docTitle: docTitle,
sgName: sgName,
mnGroup: mnGroup,
area: area
});
//:title/:cA
}
$scope.goHome = function() {
console.log("Level2Ctrl - goHome");
$state.go('contr.topmenu');
}
$scope.LoadSubGroups();
}])
.controller('DocumentCtrl', ["$scope", "DocmentService", "zoomPerOrientation", "$stateParams", "$ionicScrollDelegate", "$state", function($scope, DocmentService, zoomPerOrientation, $stateParams, $ionicScrollDelegate, $state) {
$scope.viewData = {};
$scope.snippet = "<p style='margin-top:40%;margin-left:40%;font-weight:bold;font-size:1.6em;' class='item item-stable'>Loading...</p>";
$scope.statusMessage = "";
$scope.title = $stateParams.mnGroup;
console.log("DocumentCtrl");
console.log("$stateParams", $stateParams);
//, $stateParams.docTitle, $stateParams.sgName, $stateParams.mnGroup, $stateParams.area
// console.log("Inside docuemtn controller");
$scope.LoadDocument = function(forceLoad) {
console.log("DocumentCtrl - LoadDocument");
DocmentService.getRowDocument($stateParams.id, $stateParams.docTitle, $stateParams.sgName, $stateParams.mnGroup, $stateParams.area, forceLoad).then(
function(data) {
// console.log("successfull", data);
$scope.viewData = data;
$scope.snippet = $scope.viewData.document;
},
function(reason) {
// console.log("Error Occured", reason);
$scope.viewData = {
"docTitle": "Error Occured!"
};
if (reason.error === "timeout") {
$scope.snippet = "<div style='margin-top:40%;margin-left:15%;font-weight:bold;font-size:1.6em;width:600px !important;padding:16px !important;line-height:120%;' class='item item-stable item-text-wrap item-complex'>Error: Unable to the load the document at this time. Please make sure you are in the network or you have already fetched the document while you were in the network!</div>";
}
// $scope.statusMessage = err;
}).finally(function() {
console.log("finally", data);
$scope.$broadcast('scroll.refreshComplete');
});
}
//below code would be refactored in near future.
//It is not a good practice adding window event listener in the controller
window.addEventListener('orientationchange', function() {
try {
if ($ionicScrollDelegate.$getByHandle('docScroll')._instances.length > 2) {
zoomPerOrientation.zoomTo('docScroll');
}
} catch (exception) {
console.log(exception);
}
});
$scope.goHome = function() {
console.log("DocumentCtrl - goHome");
$state.go('contr.topmenu');
}
$scope.LoadDocument(true);
}])
.controller('TopMenuCtrl', ["$scope", "TopMenuService", "$state", "$ionicHistory",
function($scope, TopMenuService, $state, $ionicHistory) {
$ionicHistory.clearHistory();
$scope.title = "Rules";
$scope.menuItems = [];
$scope.menuItemsLandscape = [];
$scope.flatMenuItems = [];
$scope.tileView = true;
$scope.listView = false;
$scope.portraitMode = true;
console.log("TopMenuCtrl");
TopMenuService.getMenuItems().then(function(data) {
$scope.menuItems = data.colData;
$scope.flatMenuItems = data.flatData;
$scope.menuItemsLandscape = data.threeColData;
console.log($scope.menuItems);
},
function() {
$scope.menuItems = [];
});
$scope.showMenuItem = function(title, metaTag) {
console.log("TopMenuCtrl - showMenuItem");
//$state.go('tab.menu', { topTitle: title });
$state.go('contr.menu', {
topTitle: title,
metaTag: metaTag
});
}
$scope.itemChanged = function() {
console.log("TopMenuCtrl - itemChanged");
console.log($scope.tileView);
if ($scope.tileView) {
$scope.listView = true;
$scope.tileView = false;
} else {
$scope.listView = false;
$scope.tileView = true;
}
}
// console.log(window.orientation);
function onChangeOrientation() {
console.log("TopMenuCtrl - onChangeOrientation");
try {
//landscape mode
// console.log("Orientation Changed");
if (window.orientation === 90 || window.orientation == -90) {
$scope.portraitMode = false;
}
//portrait
else {
$scope.portraitMode = true;
}
} catch (exception) {
console.log(exception);
}
}
onChangeOrientation();
window.addEventListener('orientationchange', function() {
try {
//landscape mode
// console.log("Orientation Changed");
if (window.orientation === 90 || window.orientation == -90) {
$scope.$apply(function() {
$scope.portraitMode = false;
});
}
//portrait
else {
$scope.$apply(function() {
$scope.portraitMode = true;
});
}
} catch (exception) {
console.log(exception);
}
});
}
])
.controller('LoginController', ["$scope", "$location", "$ionicHistory", '$timeout', '$ionicLoading', '$state',
function($scope, $location, $ionicHistory, $timeout, $ionicLoading, $state) {
$scope.username = "Guest";
$scope.password = "Abcd123";
// $ionicNavBarDelegate.showBar(false);
$scope.login = function(password) {
console.log("LoginController - login");
if (password) {
$ionicLoading.show({
content: 'Loading',
animation: 'fade-in',
showBackdrop: true,
template: '<p class="item-icon-left bar-header"><ion-spinner icon="lines"/></p>',
maxWidth: 200,
showDelay: 0
});
window.localStorage.setItem("Pswd", password);
$ionicHistory.nextViewOptions({
disableAnimate: true,
disableBack: true
});
$timeout(function() {
$ionicLoading.hide();
//$location.path("/tab/topmenu");
$state.go('contr.topmenu');
}, 1000);
}
}
}
])
.controller('AccountCtrl', function($scope) {
$scope.settings = {
enableFriends: true
};
});
Please let me know if you need any other info.Also, currently I do support local cache to cache categories locally, but not pre-cached. Is there a way to retrieve these documents beforehand? Please check my loaddocuments section which deals with loading document url's once you click on the specific item.
Please refer this I've already explained everything with programming approach.
StackOverflow Solution Link
You can use this explained approach, and adding for others who are looking for answer to this question.
I need to pass a selected value from a directive that I am using in several places. It is a select input field that I need to get a selected value from.
This is how the directive looks like:
angular.module('quiz.directives')
.directive('fancySelect', function($rootScope, $timeout) {
return {
restrict: 'E',
templateUrl: 'templates/directives/fancySelect.html',
scope: {
title: '#',
model: '=',
options: '=',
multiple: '=',
enable: '=',
onChange: '&',
class: '#'
},
link: function(scope) {
scope.showOptions = false;
scope.displayValues = [];
scope.$watch('enable', function(enable) {
if (!enable && scope.showOptions) {
scope.toggleShowOptions(false);
}
});
scope.toggleShowOptions = function(show) {
if (!scope.enable) {
return;
}
if (show === undefined) {
show = !scope.showOptions;
}
if (show) {
$rootScope.$broadcast('fancySelect:hideAll');
}
$timeout(function() {
scope.showOptions = show;
});
};
scope.toggleValue = function(value) {
if (!value) {
return;
}
if (!scope.multiple) {
scope.model = value;
console.log(scope.model);
return;
}
var index = scope.model.indexOf(value);
if (index >= 0) {
scope.model.splice(index, 1);
}
else {
scope.model.push(value);
}
if (scope.onChange) {
scope.onChange();
}
};
scope.getDisplayValues = function() {
if (!scope.options || !scope.model) {
return [];
}
if (!scope.multiple && scope.model) {
return scope.options.filter(function(opt) {
return opt.id == scope.model;
});
}
return scope.options.filter(function(opt) {
return scope.model.indexOf(opt.id) >= 0;
});
};
$rootScope.$on('fancySelect:hideAll', function() {
scope.showOptions = false;
});
}
};
});
When I do console.log(scope.model); I get the selected value, but I am not sure how to get it and use it in my controller?
This is the controller:
angular.module('quiz.controllers')
.controller('ProfileController', function(
$scope,
$state,
$stateParams,
UserService,
$auth,
MessageService,
$ionicLoading,
AppSettings,
$timeout,
AvatarService,
PushService,
$http
) {
$scope.user = UserService.get();
$scope.profilePromise = {};
if ($scope.user.player.avatar == ""){
$scope.user.player.avatar = AvatarService.getRandom();
}
$http.get(AppSettings.apiUrl + '/years')
.then(function(result) {
$scope.years = result.data;
});
$scope.updateUser = function(form) {
if (!form.$valid) {
var message = "Ugyldig data i skjema. Sjekk felter markert med rødt.";
MessageService.alertMessage(message);
return;
}
saveUser($scope.user);
};
$scope.getNextAvatar = function() {
$scope.user.player.avatar = AvatarService.getNext($scope.user.player.avatar);
};
$scope.getPreviousAvatar = function() {
$scope.user.player.avatar = AvatarService.getPrevious($scope.user.player.avatar);
};
var saveUser = function(user) {
$scope.profilePromise = UserService.save(user);
$scope.profilePromise.then(function(result) {
$scope.user = result.data.user;
PushService.init();
PushService.getDeviceId().then(function(id) {
UserService.addDevice(id);
});
if ($stateParams.register) {
$state.go('main.front');
}
}, function(error) {
var message = "Kunne ikke lagre bruker. Melding fra server: " + error.data.message;
MessageService.alertMessage(message);
});
};
});
You already have an onChange binding in the scope, so why don't you use that one?
In your directive:
if (scope.onChange) {
scope.onChange({ $value: scope.model });
}
Then pass a controller function to your directive:
<fancy-select on-change="onChange($value)"></fancy-select>
In your controller:
$scope.onChange = function(val) {
// do something with the value
}
I have a directive and I need to give her a setting to change my view based on this parameter.
<ta-card type="unlock"
class="parent-card"
owner="currentUser"
ng-repeat="unlockCard in unlockedCards"
title="{{unlockCard.title}}">
</ta-card>
Here i send param title and i want recup here
<div class="card-footer">
<div class="card-info left floated">
<div class="info" ng-model="title"></div>
<span class="sub-info"
ng-if="$root.response==undefined">Chargement</span>
<span class="sub-info" translate="card.subtitle.soon_available" ng-if="$root.response!=undefined"></span>
</div>
<span class="flip-btn white"
ng-if="options.flip"
ng-click="flipCard(model.parentId != undefined)">
<i class="chevron right icon"></i></span>
</div>
</div>
Edit :
That's my directive, but i'm not sure that could be help you
.directive('taCard', ['appAuth', 'taCardService', '$rootScope', '$timeout',
function (appAuth, taCardService, $rootScope, $timeout) {
return {
restrict: 'E', // cards must be always an element, by convention
transclude: false,
replace: true,
scope: {
owner: '=?', //this is going to be an User Object
model: '=?',
readonly: '=?', //this makes form fields readonly,
transcludeData: '=?',
childLoad: '#',
unlockType: '#'
},
link: function (scope, element, attrs) {
// console.log(scope.model);
console.log(scope);
scope.showFront = true;
scope.displayChildCards = false;
scope.elementId = 'card-' + parseInt(Math.random() * 100000000000);
element.attr('id', scope.elementId);
scope.isEditable = false;
scope.options = taCardService.getOptions(attrs.type);
// console.log(scope.options);
scope.model = angular.isDefined(scope.model) ? scope.model : {};
if (scope.options.hasOwner) {
taCardService.hasAccess(scope.owner)
.then(function (access){
if (access === true) {
//set if is editable
appAuth.currentUser()
.then(function (currentUser) {
scope.currentUser = currentUser;
if (scope.owner.id === scope.currentUser.id) {
scope.isEditable = true;
}
});
} else {
// destroy the card if user doesn't have acccess
element.remove();
scope.$destroy();
}
});
}
if (taCardService.hasService(attrs.type)) {
taCardService.onLoad(attrs.type, scope, element);
taCardService.setEvents(attrs.type, scope);
scope.service = taCardService.getService(attrs.type);
}
// get the model data
if (taCardService.hasService(attrs.type)) {
taCardService.getModel(attrs.type, scope)
.then(function (data) {
scope.model.data = data.model;
},
function (error) {
console.log('impossible to get the model: status ' + error.status);
});
}
if (!angular.isDefined(scope.owner) && scope.options.hasOwner) {
// alert to the sleepy developer that must pass the owner
console.log('hey! you forgot the owner!');
return;
}
}
}
}
])
My factory
window.angular && (function(angular) {
'use strict';
angular.module('taApp')
.factory('taUnlockCard', ['$q','$rootScope', function($q,$rootScope) {
// JE RECUPERE LE TITRE DE LA CARTE ???
$rootScope.title="Titre";
return {
};
}]);
})(window.angular); // jshint ignore:line
I can't understand why it does not update the $scope.user_free_status when I set a user free but when I unset the parameter it works perfectly. I need to reload page in one case and not the other...
The datas fetched are stored in the localstorage.
Here is the code:
.state('app', {
url: "/app",
abstract: true,
templateUrl: "templates/menu.html",
controller: 'InitialCtrl',
resolve: {
theUserFreeStatus: function(DataService) {
return DataService.getUserFreeStatus();
}
}
})
Controller:
.controller('InitialCtrl', function($scope, $state, DataService ,FreeService, SharedService, theUserFreeStatus) {
// Showing set free but not unset or not
if (FreeService.isSetFree()) {
$scope.showSetFree = false;
$scope.showUnSetFree = true;
} else {
$scope.showSetFree = true;
$scope.showUnSetFree = true;
}
// Show the Free status set when arriving on page/app
$scope.user_free_status = theUserFreeStatus;
// Set user as Free
$scope.setFree = function(activity, tags) {
FreeService.setFree(activity, tags).success(function() {
console.log($scope.user_free_status);
$scope.user_free_status = DataService.getUserFreeStatus();
console.log($scope.user_free_status);
$scope.showSetFree = false;
$scope.showUnSetFree = true;
SharedService.goHome();
})
}
//// Free status unset
$scope.unsetFree = function() {
FreeService.unsetFree().success(function() {
$scope.user_free_status = [];
$scope.showSetFree = true;
$scope.showUnSetFree = false;
SharedService.goHome();
});
};
})
The services:
.factory('FreeService', function(WebService, $localstorage, $ionicPopup, DataService, $sanitize, CSRF_TOKEN) {
var cacheFreeStatus = function(free_status) {
$localstorage.setObject('user_free_status', free_status)
};
var uncacheFreeStatus = function() {
$localstorage.unset('user_free_status')
}
return {
setFree: function(activity, tags) {
var status = { SOME STUFF BLABLABLA };
var setFree = WebService.post('setstatus/', sanitizeStatus(status));
setFree.success(function(response) {
console.log('available' + response.flash);
cacheFreeStatus(response.status_response);
})
setFree.error(freeError)
return setFree;
},
unsetFree: function() {
var details = {OTHER STUFF};
var unsetFree = WebService.post('unsetstatus/', details);
unsetFree.success(function(response) {
console.log('unset ' + response.flash);
uncacheFreeStatus(response.status_response);
})
unsetFree.error(freeError)
return unsetFree;
},
isSetFree: function() {
return $localstorage.get('user_free_status');
}
}
})
.service('DataService', function($q, $localstorage) {
return {
activities: $localstorage.getObject('activities'),
getActivities: function() {
return this.activities;
},
user_free_status: $localstorage.getObject('user_free_status'),
getUserFreeStatus: function() {
return this.user_free_status;
}
}
})
* Local Storage Service
------------------------------------------------------*/
.factory('$localstorage', ['$window', function($window) {
return {
set: function(key, value) {
$window.localStorage[key] = value;
},
unset: function(key) {
localStorage.removeItem(key);
},
get: function(key, defaultValue) {
return $window.localStorage[key] || defaultValue;
},
setObject: function(key, value) {
$window.localStorage[key] = JSON.stringify(value);
},
getObject: function(key) {
return JSON.parse($window.localStorage[key] || '{}');
}
}
}])
When setting the user's status, the console returns that the $http call worked but an empty array for the $scope variable I try to set. Once I reload the page I can see the updates displayed. If I unset the user's status, the $scope is properly updated without need to reload the page.
The Webservice is just the $http call.
What am I missing here to have the $scope.user_free_status updated correctly without having to reload the page??
Thanks for your time!
Your data service is injected as service but you have not appended the functions to this.rather you have returned it as part of literal like u do in factory
I have a widget like directive called waComments, it loads components via a RESTful service and displays them. In my view I'm using ng-repeat to loop over them and to render them with a button that if pressed Shows a new reply to form. This his handled by the waCommentsReply directive. One waComments widget has many child directives of type waCommentsReply. When the form is filled and submitted I want to add the new comment on top of my comments list. So both directives have to share the comments data.
I've tried to implement this here Sharing data between directives but without much success, the comment data is not updated when I add a new comment. I see that the RESTful API calls work and the data is returned, so this is not an issue.
Why is my implementation of Sharing data between directives not working in my case?
waCommentsReply directive:
waFrontend.directive('waCommentsReply', ['$rootScope', 'Comment', 'WaFormValidation', 'WaCommentStore', function($rootScope, Comment, WaFormValidation, WaCommentStore) {
return {
restrict: 'E',
templateUrl: '/stubs/comment-form.html',
transclude: true,
scope: {
replyTo: '#replyTo',
replyFormList: '=replyFormList',
loggedIn: '#loggedIn',
model: '#model',
id: '#id',
cancelButton: '#cancelButton'
},
controller: function($scope) {
$scope.comments = WaCommentStore;
if ($scope.cancelButton == undefined) {
$scope.cancelButton = true;
} else {
$scope.cancelButton = false;
}
$scope.comment = $scope.commentForm = {
Comment: {
author_name: '',
body: '',
model: $scope.model,
foreign_key: $scope.id,
parent_id: $scope.replyTo
}
};
$scope.$watch('replyFormList', function (newValue, oldValue) {
if (newValue) {
$scope.replyFormList = newValue;
}
});
if ($scope.loggedIn == undefined) {
$scope.loggedIn = false;
}
/**
* Handles the submission and response of a reply
*
* #return void
*/
$scope.reply = function() {
Comment.add($scope.comment).then(function(result) {
if (result.status == 'fail' || result.validation != undefined) {
$scope.validationErrors = result.validation;
WaFormValidation.validate(result.validation, $scope.commentForm);
} else if (result.status == 'success') {
//$scope.$parent.comments.unshift(result.data.comment);
//$scope.comments.unshift(result.data.comment);
$scope.comments.comments.unshift(result.data.comment);
//WaCommentStore.append($scope.model, $scope.id, result.data.comment);
$scope.comments, $scope.id, result.data.comment
$scope.comment = {};
$scope.replyFormList[$scope.replyTo] = false;
}
});
};
$scope.close = function() {
$scope.comment = {};
if ($scope.replyFormList[$scope.replyTo] != undefined) {
$scope.replyFormList[$scope.replyTo] = false;
}
}
}
};
}]);
WaCommentStore directive:
waFrontend.factory('WaCommentStore', function() {
return {
comments: []
};
});
waComments directive:
waFrontend.directive('waComments', ['$rootScope', 'Comment', 'WaCommentStore', function($rootScope, Comment, WaCommentStore) {
return {
restrict: 'E',
templateUrl: '/stubs/comments.html',
scope: {
model: '#commentModel',
id: '#commentFk'
},
controller: function($scope) {
$scope.comments = WaCommentStore;
$scope.loaded = false;
$scope.loadedMore = true;
$scope.currentPage = 1;
$scope.loggedIn = false;
$scope.paging = {};
$scope.replyFormList = {};
Comment.comments($scope.model, $scope.id).then(function(result) {
$scope.comments.comments.push.apply($scope.comments.comments, result.data.comments);
$scope.loggedIn = result.data.loggedIn;
$scope.paging = result.paging.Comment;
$scope.loaded = true;
});
$scope.loadMore = function() {
$scope.loadedMore = false;
if ($scope.paging.nextPage == false) {
//return false;
}
var options = {
page: $scope.paging.page + 1
};
Comment.comments($scope.model, $scope.id, options).then(function(result) {
$scope.comments.comments.push.apply($scope.comments.comments, result.data.comments);
$scope.paging = result.paging.Comment;
$scope.loadedMore = true;
});
};
$scope.submitComment = function() {
//alert($scope.author_name + $scope.body);
};
$scope.reply = function(replyId) {
$scope.replyFormList[replyId] = true;
}
}
};
}]);
since in both directive you defined scope: {} basically it means you defined those directives to use isolated scope.
with isolated scope, a scope/directive can't see what is in the parent scope.
however parent scope, can be affected by the child scope changes with 2 way binding definition.
https://docs.angularjs.org/guide/scope
try changing the shared data like this
waFrontend.factory('WaCommentStore', function() {
var comments = [];
var getComments = function() { return comments; }
var setComments = function(data) { comments = data; }
return {
getComments : getComments ,
setComments : setComments
};
});
I wanted to put it as a comments, but it would have been difficult to understand for you.
Please let me know if this works, else I will delete this answer.