Update directive in parent scope - javascript

I'm pretty new to angular js, currently, it's going well but now I have a question.
I have a template with a topnav and a contentpart. All with its own controller.
With a button I can open a "submenu" where I can choose data from the database, within the "Liquid"-section. Thats working pretty well.
Since the Topnav is rendered at the login of the page, the topnav wont be rendered again.
If I add a Liquid in the content section, I have to reload the data behind the "Liquid"-Dropdown.
That dropdown is encapsulated in a directive:
function liquidselect(Data){
return {
restrict: 'AE',
templateUrl: 'views/controls/liquid_select.html',
scope: {
selectedValues : '='
},
link: function(scope) {
},
controller: function ($scope) {
//
Data.post('ownrecipes').then(function (results) {
$scope.searchRes = results;
});
// debugger;
//$scope.searchRes = RecipeDataService.data;
$scope.disabled = undefined;
$scope.searchEnabled = false;
$scope.searchRes = [];
$scope.flavoring = {amount: {}};
$scope.updateModelValue = function (selected) {
// console.log(selected);
//
$scope.selectedValues = selected;
};
}
}
}
The communication to the server is done by a factory:
app.factory("Data", ['$http', 'toaster',
function ($http, toaster ) { // This service connects to our REST API
// var deffered = $q.defer();
var serviceBase = 'api/v1/';
var obj = {};
obj.toast = function (data) {
toaster.pop(data.status, "", data.message, 3000, 'trustedHtml');
}
obj.get = function (q) {
return $http.get(serviceBase + q).then(function (results) {
return results.data;
});
};
obj.post = function (q, object) {
return $http.post(serviceBase + q, object).then(function (results) {
return results.data;
});
};
obj.put = function (q, object) {
return $http.put(serviceBase + q, object).then(function (results) {
return results.data;
});
};
obj.delete = function (q) {
return $http.delete(serviceBase + q).then(function (results) {
return results.data;
});
};
return obj;
}]);
How can I update/reload the data of the directive from a child scope? Is there any chance?
Here is a plunker which showcases my problem and want I want to do:
http://plnkr.co/edit/bNANkQYZfBaS4CHH3dwX
I hope it's helpful for you :-)
Layout:
Basic Layout

Related

Angular - pass info from array from one controller to another

I'm having a little problem trying to pass a service within controllers.
What I'm trying to do is a shopping cart, I have a list of items and when I hit a button, those items get added to the cart, then I want to list those items in the cart in a separate page using a separate controller, so I'm trying to use a factory for the cart, but I don't know if you can set a factory object within a controller.
Here's my code, hope you can point me in the right direction.
var app = angular.module("Shop", []);
app.factory('DataService', function () {
var cart = [];
var set = function (data) {
cart = data;
}
var get = function () {
return cart;
}
});
app.controller("catalogController", function ($scope, $http) {
$scope.bookStore = {
selected: {},
books: null
};
$scope.cart = [];
$http.get("json/books.json")
.success(function (data) {
console.log(data);
$scope.bookStore.books = data;
})
.error(function (err) {
});
$scope.addToCart = function (book) {
var found = false;
$scope.cart.forEach(function (item) {
if (item.id === book.id) {
item.quantity++;
found = true;
}
});
if (!found) {
$scope.cart.push(angular.extend({
quantity: 1
}, book));
}
};
$scope.removeFromCart = function (item) {
var index = $scope.cart.indexOf(item);
$scope.cart.splice(index, 1);
};
$scope.getCartPrice = function () {
var total = 0;
$scope.cart.forEach(function (product) {
total += product.price * product.quantity;
});
return total;
};
});
app.controller("checkoutController", function ($scope, DataService) {
$scope.cart = DataService;
});
Change things a bit to something like:
app.factory('DataService', function () {
var cart = [];
return {
set: function (data) {
cart = data;
},
get: function () {
return cart;
},
add: function (item) {
cart.push(item);
}
}
});
...
app.controller("checkoutController", function ($scope, DataService) {
$scope.cart = DataService.get();
});
And then move the $http.get method and all the operations on the card in the other controller to functions in the factory and declare them on the same way as the above Dataservice.get()
You should do something like this:
A service is a singleton in angular js, that's mean you only have one instance of this class in your app.
var app = angular.module("Shop", []);
app.factory('DataService', function ($http) { // usualy your service is the one which call your API (not your controller)
var cart = null; // the cart array is set in the instance of the class as private
return{ // here you declare all the functions you want to call from outside (your controllers)
set : function (data) {
cart = data;
},
get: function(){
return cart;
},
getFromAPI = function () { // the code you have in your controller should goes here
return $http.get("json/books.json")
.success(function (data) {
console.log(data);
cart = data; //now you set you cart variable
})
.error(function (err) {
});
},
});
Then in your controllers:
app.controller("catalogController", function ($scope, DataService) { // include your service as a dependency
$scope.bookStore = {
selected: {},
books: null
};
$scope.cartInCatalogController = DataService.get(); // it will set the value of cart that's in your service to your controller's scope
if(!$scope.cartInCatalogController) {// if it's null so call the API
DataService.getFromAPI()// this function should return a promise
.success(function(data){// so call the success function
$scope.cartInCatalogController = data;
})
.error(function(error){
// do something here if you want
});
});
You can do the same in your other controller.
About the addToCard function and other stuff I let you find it by yourself.
You can start from here :)

two button on two different views calling the same function, angularjs

I have a SPA with two different views one for subjects and one for student,
in subject view I have a save button in app/views/subject/subject.html:
<button type="button" class="btn btn-warning" ng-click="saveInfo()">
Save
</button>
I want to add the same function in the student views , saveInfo() pass the data into a service in the app factory which save the data in DB through fill_table.php.
the app factory in app/javascript/services.js:
var app = angular.module('myApp');
app.factory("services", ['$http', function($http) {
var serviceBase = 'http://localhost/php/';
var obj = {};
document.title = "myApp on " + serviceBase;
obj.postData = function (user, data) {
return $http.post(serviceBase + 'fill_table.php', { "data": data, "user": {'username': user.name, 'password': user.password }).then(function (results) {
return results.data;
});
};
saveInfo() is in app/views/subject/subject.js:
$scope.saveInfo = function() {
console.log("saveInfo");
$scope.loadingInstance = $modal.open({
animation: $scope.animationsEnabled,
templateUrl: 'modalLoading.html',
size: "l",
});
return getChanges( $indexedDB, $q).then( function(responsesArray) {
var jsonData = {};
$scope.errorInstance = undefined;
for (var i=0; i < DB_TABLES.length; i++) {
var table = DB_TABLES[i];
var items = responsesArray[i]
if (items.length > 0){
jsonData[table] = items;
}
}
console.log(JSON.stringify(jsonData));
return services.postData($scope.selectedUser, jsonData);
})
}
I want to add the mentioned button into app/views/student/student.html. i tried and copied the code from the subject.js into Student but for some reason it does not work eventhough i checked everything was correct so is there a way to only that function from subject.js into Student.html
note 1 getChanges() is another function get the inserted info and pass it into saveinfo().
note 2 right now I can save the info inserted student view by pressing save button in subject view
If I understand you correctly, you have two html files and two controller (student and subject). To share data/functions between these, you could use a service or factory to handle all your http request. This is reusable and accessible from all your controllers.
app.factory("services", ['$http', function($http) {
var postStudent = function (student) {
return $http.post("api/Student/Post", student);
};
var getChanges = function (){
return $http.get("api/Student/Changes", student);
};
return {
postStudent : postStudent,
getChanges : getChanges
};
}])
Now you can use can call the services from your controller as you see fit.
app.controller('StudentController', ['service', function(service){
service.postStudent(student).then(function successCallback(response) {
console.log('success');
}, function errorCallback(response) {
console.log('error ' + response);
});
service.getChanges().then(function successCallback(response) {
console.log('success');
}, function errorCallback(response) {
console.log('error ' + response);
});
}]);
app.controller('SubjectController', ['service', function(service){
service.postStudent(student).then(functionsuccessCallback(response){
},
function errorCallback(response) {
});
service.getChanges().then(function successCallback(response) {
},
function errorCallback(response) {
});
}]);
Note that the above has not been implemented, but should provide you with an outline.

Directive to Hide/Show elements based on Session Service - AngularJS

Following up this answer, I was trying to build two directives to allow/deny elements to be visible by the end user.
angular.module('app.directives').directive('deny', ['SessionTool', function (SessionTool) {
return {
restrict: 'A',
link: function (scope, elem, attrs) {
scope.$watch(SessionTool.user, function (value, oldValue) {
var list = attrs.deny.split(',');
if (SessionTool.hasAnyRole(list))
return elem.hide();
return elem.show();
});
}
}
}]);
My problem is that when I do make the logon, the $watch function is not being called again to make the invisible element appear.
A resume of my SessionTool is listed below.
angular.module('app.tools').factory('SessionTool', ['$cookies', function ($cookies) {
var _cookieKey = 'user';
return {
user: {},
init: function () {
var u = $cookies.get(_cookieKey);
try {
u = angular.fromJson(u);
this.user = u;
} catch (e) {
console.log('invalid json');
}
},
login: function (u) {
this.user = u;
$cookies.putObject(_cookieKey, u, {path: '/'}); // #TODO encrypt the whole JSON before saving it to cookies.
},
...
};
}]);
Anybody could point out why the $watch isn't being fired?
Thanks in advance.
I think that your directive is currently watching an anonymous variable SessionTool.user in your directive scope not the actual variable. I suggest going with this approach instead.
angular.module('app.tools').factory('SessionTool', ['$cookies','$rootScope', function ($cookies) {
var _cookieKey = 'user';
var _user = {};
return {
setUser: function(user) {
_user = user;
$rootScope.$broadcast('SessionToolChange');
}
getUser: function() {
return _user;
}
init: function () {
var u = $cookies.get(_cookieKey);
try {
u = angular.fromJson(u);
this.user = u;
} catch (e) {
console.log('invalid json');
}
},
login: function (u) {
this.user = u;
$cookies.putObject(_cookieKey, u, {path: '/'}); // #TODO encrypt the whole JSON before saving it to cookies.
},
...
};
}]);
angular.module('app.directives').directive('deny', ['SessionTool', function (SessionTool) {
return {
restrict: 'A',
controller: function (scope, elem, attrs) {
scope.$on('SessionToolChange', function (value, oldValue) {
// get the user and do your stuff.
});
}
}
}]);

Scope of Datas not updating after a $http AngularJS

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

AngularJS share data bettween parent and child scope directives

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.

Categories