Updating directive based on change in service value AngularJS - javascript

I have a basic app currently that has a list of names in a sidebar nav populated from a json call to my server. When the user clicks on a name in the sidebar, it updates the nameService to the name clicked on by the user.
When the nameService gets updated, I wanted to name-data view to make another json call the the server for the correct json file based on the name that the user clicked on.
I am having difficulty updating a view based on changes in a value contained in my service. I have two controllers and a service currently in my AngularJS app as follows:
app.js
var app = angular.module("myapp", ['ui.bootstrap']);
app.directive("sideBar", ['$http', 'nameService', function($http, nameService) {
return {
restrict: 'E',
templateUrl: "views/sidebar.html",
controller: function($scope) {
$scope.updateName = function(name) {
nameService.setName(name);
};
$http.get('../data/names.json').
success(function(data, status, headers, config) {
$scope.names = data;
});
}
};
}]);
app.directive("nameData", ['$http', 'nameService', function($http, nameService) {
return {
restrict: 'E',
templateUrl: "views/name-data.html",
controller: function($scope) {
$scope.service = nameService;
var path = "../data/" + $scope.service.name + ".json";
$http.get(path).success(function(response) {
$scope.info= response.info;
});
}
};
}]);
app.service('nameService', ['$http', function($http) {
this.name = "TestName";
this.setName = function(name) {
this.name = name;
};
this.getName = function() {
return this.name;
};
}]);
How can I update the nameData view whenever the user clicks on the sidebar nav and updates the nameService.name property?
I tried putting $scope.service.name under a watch but that didn't seem to do anything.
Is there some form of angular magic I can use to dynamically make new json calls when a new user is selected from the name list contained in my side bar?

maybe angular event broadcasts?
add rootScope to service and broadcast an event on name change:
app.service('nameService', ['$http','$rootScope', function($http,$rootScope) {
this.name = "TestName";
this.setName = function(name) {
this.name = name;
$rootScope.$broadcast('nameService-nameChanged');
};
this.getName = function() {
return this.name;
};
}]);
and then bind to that event on your directive controller scope:
app.directive("nameData", ['$http', 'nameService', function($http, nameService) {
return {
restrict: 'E',
templateUrl: "views/name-data.html",
controller: function($scope) {
$scope.service = nameService;
//turned your load mechanism in to a function
$scope.loadNameData = function(){
var path = "../data/" + $scope.service.name + ".json";
$http.get(path).success(function(response) {
$scope.info= response.info;
});
}
//initial load
$scope.loadNameData();
//subscribe to broadcast event, this will call $scope.loadNameData when the 'nameService-nameChanged' event is broadcast
$scope.$on('nameService-nameChanged',$scope.loadNameData);
}
};
}]);

Related

AngularJS Custom Service is not working

This is a simple service I created:
var app = angular.module('myApp', ['ngRoute']);
app.service('UserService', function() {
this.user = {firstName:"",middleName:"",lastName:"",email:"",dob:""};
this.addUser = function (user) {
users.push(user);
}
this.displayUser = function (user) {
this.user = user;
}
});
This is the controller where I want to use the service:
app.controller('DisplayUserController', ['$scope','UserService',
function($scope, UserService) {
$scope.user = UserService.user;
}]);
This is the HTML where I am passing the user object to user directive:
<div ng-controller="DisplayUserController">
<div>{{user.firstName}}</div>
<div>{{user.middleName}}</div>
<div>{{user.lastName}}</div>
</div>
Why am I getting "Unknown provider: userProvider <- user" error? Please help.
You need to bind the ngModel to your directive:
.directive('user', function() {
return {
restrict: 'E',
scope:{
'user': '=ngModel'
},
templateUrl:'display-single-user.html',
controller: function($scope) {
var user = $scope.user;
$scope.firstName = user.firstName;
$scope.middleName = user.middleName;
$scope.lastName = user.lastName;
$scope.email = user.email;
$scope.dob = user.dob;
}
};
});
There was a problem in my directive, I was using internal controller that also needed the UserService therefore added it as a dependency and it started working. Now, please let me know if this is a correct practice to follow.
angular.module('myApp').directive('user', ['UserService', function() {
return {
restrict: 'E',
templateUrl:'templates/display-single-user.html',
controller: function($scope, UserService) {
$scope.firstName = UserService.user.firstName;
$scope.middleName = UserService.user.middleName;
$scope.lastName = UserService.user.lastName;
$scope.email = UserService.user.email;
$scope.dob = UserService.user.dob;
}
};
}]);

How to pass form data to another page?

im using angularJS v 1.5.6 and want to know how to pass my form data correctly with $location.path.
Here is my code Page A:
<form>
...
<button type="submit" ng-click="submit(formData)">submit</button>
</form>
JS:
app.config(['$routeProvider', function ($routeProvider) {$routeProvider
// Home
.when("/", {
templateUrl: "A.html",
controller: "ACtrl"
})
.when("/B/", {
templateUrl: "B.html",
controller: "BCtrl"
})
//fallback url if nothing matches
.otherwise({
redirectTo: '/'
});
}]);
app.controller('ACtrl', function ( $scope, $location, $http) {
$scope.formData = {};
$scope.submit = function() {
$location.path("/B/" + $scope.formData );
};
});
//controller for B page
app.controller('BCtrl', ['$scope', '$routeParams',
function($scope,$routeParams) {
$scope.formData = $routeParams.formData;
}]);
it is a pretty simple example, but i cant figure out how to solve it :(
By clicking the submit nothing happens. If i remove the $scope from $scope.formData i get a error like: Error: formData is not defined.
The terms in formdata are available, i tested it with console.log($scope.formData) and everything is ok.
here is the link plunker: https://plnkr.co/edit/K5zwcmRRyom5HR4a5Q9o
EDIT
the only issue is now, how to handle the select object correctly in the foreach loop. Need help please
You can do it by creating a service and using setter/getter in order to transfer a variable.
For example like this: https://plnkr.co/edit/IuTXsVLU7dq3TylfnSYP?p=preview
app.service('TransferService', [function(){
var savedData,
service = {
getData: getData,
setData: setData
}
function getData(){
return savedData
}
function setData(data){
savedData = data
}
return service
}])
Don't use location.path...
You could either use a service or use localstorage (or some other browser storage mechanism [sessionStorage, indexdb].
Service Method Below
app.service("SomeService", function () {
var value = null;
this.set = function (val) {
value = val;
return this;
}
this.get = function () {
return value;
}
})
app.controller("ACtrl", function ($scope, SomeService) {
$scope.formData = {};
$scope.submit = function() {
//Assuming you've populated it with some data...
SomeService.set($scope.formData);
$location.path("/B/");
};
})
app.controller("BCtrl", function ($scope, SomeService) {
$scope.formData;
(function () {
//Check that the data is present in the SomeService service.
var dataFromACtrl = SomeService.get();
if (dataFromACtrl) {
$scope.formData = dataFromACtrl;
}
})();
})
Using localStrorage below, could be sessionStorage.
app.controller("ACtrl", function ($scope, SomeService) {
$scope.formData = {};
$scope.submit = function() {
//Assuming you've populated it with some data...
window.localStorage.setItem("form_data", JSON.stringify($scope.form_data));
$location.path("/B/");
};
})
app.controller("BCtrl", function ($scope, SomeService) {
$scope.formData;
(function () {
var dataFromACtrl = window.localStorage.getItem("form_data");
if (dataFromACtrl) {
$scope.formData = JSON.parse(dataFromACtrl);
}
})();
})
Note
Using the localStorage example you would need to do some clean-up, after doing whatever you want to do with that data in Bctrl you'd want to clear the entry in localstorage using either of the below lines of code:
window.localStorage.removeItem("form_data");
delete window.localStorage["form_data"];

How do i pass changing data into a modal?

I'm trying to pass a changing scope variable into a modal window. I'm having trouble allowing the variable to change once the modal is open. Currently I have the data being passed to a controller when the modal is opened:
scope.open = function (roomname, image) {
console.log("clicked modal");
console.log("roomName: " + roomname);
console.log("image: " + image);
scope.imageContents = image;
console.log("scope.imageContents: " + scope.imageContents);
scope.modalInstance = $modal.open({
animation: scope.animationsEnabled,
templateUrl: 'tpl/modal-template.tpl.html',
controller: 'ModalInstanceCtrl',
resolve: {
items: function () {
console.log("scope.imageContents in resolve: " + scope.imageContents);
return scope.imageContents;
},
compassHeading: function () {
console.log("scope.imageContents in resolve: " + scope.compassHeading);
return scope.compassHeading;
}
}
});
};
and my controller:
angular.module('TestApp').controller('ModalInstanceCtrl',function ($scope, $modalInstance, items, compassHeading) {
'use strict';
$scope.items = items;
$scope.selected = {
item: $scope.items
};
$scope.compassHeading = compassHeading;
});
The compass Heading variable is constantly being updated, so I am trying to get the compassHeading variable to show these changes in the modal.
You could use a service which has your variable along with other variables:
angular.module('TestApp')
.service('TestService', [function () {
return {
model: {
'compassHeading': null
}
};
}]);
And in your main controller, you could use it like:
angular.module('TestApp')
.controller('MainController', ['$scope', 'TestService', function ($scope, testService) {
$scope.model = testService.model;
...
}]);
And in your $modal controller, you could do the same:
angular.module('TestApp')
.controller('ModalInstanceCtrl', ['$scope', 'TestService', function ($scope, testService) {
$scope.model = testService.model;
}]);
Then, anytime the value of compassHeading needs to be changed, you could just change it using the normal: $scope.model.compassHeading = <some_value_here>;.
Also, the value of compassHeading, if changed outside the controllers, will also be changed inside the controllers, since the model object of the service is called by reference.

Sharing data between directives AngularJS

I have been trying out some AngularJS tutorials and dabbling around trying to create a simple website.
I have a directive that creates a side navigation bar and populates the list of items from some json data stored on my server. The name list is populated without an issue.
The problem is that I need to share that name between several controllers, but I am not having any luck doing so.
My app.js contains:
var app = angular.module("Myapp", ['ui.bootstrap']);
app.service('nameService', function() {
var name = "";
this.setName = function(name) {
this.name = name;
}
this.getName = function() {
return name;
}
});
app.directive("sideBar", ['$http', function($http) {
return {
restrict: 'E',
templateUrl: "views/sidebar.html",
controller: function($scope) {
$scope.updateName = function(name) {
alert(name);
};
$http.get('../data/names.json').
success(function(data, status, headers, config) {
$scope.names = data;
}).error(function(data, status, headers, config) { });
}
};
}]);
From what I've read you should just be able to inject the service as a dependency as follows:
app.directive("sideBar", ['$http', 'nameService', function($http, nameService) {
Then I should be able to update the value like so:
$scope.updateName = function(name) {
nameService.setName(name);
};
However, when I try to inject the dependency it breaks the entire directive and the sidebar will no longer load.
I have been pulling my hair out trying to figure out why it breaks without much luck. Is there something I am missing? Or am I going about this the complete wrong way?

Angularjs How to communicate between two modals

What I am trying to do here is:
Type in the new language name and click "Add" button, the new language will be added into the existing object.
For example: the existing object: {"default": "English"}, When I type in "German", a new object is added like this: {"default": "English", "German": "German"}
Here is my PLUNKER.
Could someone help me on that? Thanks so much, I will appreciate!
I would prefer to use events. Just subscribe one piece on some event like:
$rootScope.$on('myEvent', function(event, info){
// do something
});
And another one will fire it:
scope.$broadcast('myEvent', info);
The system glitched when I was trying to save your plunkr or I don't have a permission so here the code:
var app = angular.module('plunker', ['ui.bootstrap']);
app.factory('Data', function(){
var data =
{
Language: ''
};
return {
setLanguage: function(language) {
data.Language = language;
}
}
})
var ModalDemoCtrl = function ($scope, $modal, $log) {
$scope.languages = {"sch": "Simple Chinese"};
$scope.$on('newLanguageAdded', function(e, lang){
$scope.languages[lang] = lang;
});
$scope.open = function () {
var modalInstance = $modal.open({
templateUrl: 'myModalContent.html',
controller: ModalInstanceCtrl,
resolve: {
languages: function () {
return $scope.languages;
},
newLanguage: function () {
return $scope.newLanguage;
}
}
});
};
};
// Please note that $modalInstance represents a modal window (instance) dependency.
// It is not the same as the $modal service used above.
var ModalInstanceCtrl = function ($scope, $modal, $modalInstance, languages, newLanguage) {
$scope.languages = languages;
$scope.ok = function () {
$modalInstance.close($scope.languages);
};
$scope.cancel = function () {
$modalInstance.dismiss('cancel');
};
$scope.openDialog = function () {
var modalInstance = $modal.open({
templateUrl: 'addNewLanguageDialog.html',
controller: AddNewLanguageCtrl,
});
}
var AddNewLanguageCtrl = function ($scope, $rootScope, $modalInstance, Data){
$scope.newValue = {text: ''};
$scope.$watch('newLanguage', function(newValue) {
if(newValue) Data.setLanguage(newValue);
});
$scope.add = function () {
alert($scope.newValue.text);
$rootScope.$broadcast('newLanguageAdded', $scope.newValue.text);
$modalInstance.close($scope.languages);
}
$scope.cancel = function () {
$modalInstance.dismiss('cancel');
}
}
};
You can just copy this piece into plunkr instead yours.
Also change the layout:
<div class="modal-body">
<input ng-model="newValue.text">
</div>
Let me know if something doesn't work
You need to use a service, by definition singletons, and inject it in both models, adding a watch to the array in the service and updating accordingly in the scope of every model, from the values in the service.
An angular-ui way to achieve what you need would be to use these two basic methodologies found in the angular-ui documentation. See associated plunker for the answer below.
First is to use the close(result) inside the Instance Controller of the modal which updates the result promise property of the Instance Controller
Second is to use the result promise property to get the result(s) passed on to the close() method
Inside The AddNewLanguageCtrl is something like this
$scope.data = {newLanguage: ""};
$scope.add = function() {
$scope.close(data.newLanguage);
};
Inside the your addNewLanguageDialog.html script template
instead of using
<input ng-model="newLanguage">
use this
<input ng-model="data.newLanguage">
This is because whenever a modal is created, a new scope is created under the $rootScope(default) if a scope is not passed on to the options when the $modal.open() is invoked as stated in the angular-ui documentation. If you use newLanguage as the model then it won't receive any updates inside the AddNewLanguageCtrl. You can read this to get a better understanding of what I'm talking about regarding scopes
Inside the first modal ModalInstanceCtrl is something like this
$scope.newLanguages = [];
$scope.openDialog = function () {
var modalInstance = $modal.open({
templateUrl: 'addNewLanguageDialog.html',
controller: AddNewLanguageCtrl,
});
modalInstance.result.then(function(newLanguage) {
if(newLanguage)
$scope.newLanguages.push(newLanguage);
});
};
And then in your ModalDemoCtrl
$scope.languages = [];
$scope.open = function () {
var modalInstance = $modal.open({
templateUrl: 'myModalContent.html',
controller: ModalInstanceCtrl
});
modalInstance.result.then(function(languages) {
$scope.languages = $scope.languages.concat(languages);
});
};

Categories

Resources