Sharing values between states in AngularJS - javascript

How can I share the variable "demo" between all of my states in angular? I've tried to do this by creating a 'mainController' and placing it inside of my states along with another controller in the 'view' like shown below. But I keep getting an error saying that 'demo' is not defined when I try console.log(demo); in my states.
My Main Controller
app.controller('mainController', function ($scope,$http,$state,$window,$timeout) {
var demo = "works";
})
How I've tried to intergrate that 'mainController' within my states alongside a controller in my 'view' (NOTE: I've closed the brackets on the example I'm showing you, there's just a lot of javascript below this script)
.state('checkIn',{
controller:'mainController',
url:'/checkIn',
views: {
'main':{
templateUrl: 'templates/checkIn.html',
controller: function($scope,$http,$state,$window,$timeout){
console.log(demo);
The rest of my javascript
// Ionic Starter App
// angular.module is a global place for creating, registering and retrieving Angular modules
// 'starter' is the name of this angular module example (also set in a <body> attribute in index.html)
// the 2nd parameter is an array of 'requires'
var app = angular.module('starter', ['ionic','ui.router','service'])
.run(function($ionicPlatform) {
$ionicPlatform.ready(function() {
// Hide the accessory bar by default (remove this to show the accessory bar above the keyboard
// for form inputs).
// The reason we default this to hidden is that native apps don't usually show an accessory bar, at
// least on iOS. It's a dead giveaway that an app is using a Web View. However, it's sometimes
// useful especially with forms, though we would prefer giving the user a little more room
// to interact with the app.
if (window.cordova && window.cordova.plugins.Keyboard) {
cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);
cordova.plugins.Keyboard.disableScroll(true);
}
if (window.StatusBar) {
// Set the statusbar to use the default style, tweak this to
// remove the status bar on iOS or change it to use white instead of dark colors.
StatusBar.styleDefault();
}
});
});
app.controller('mainController', function ($scope,$http,$state,$window,$timeout) {
var demo = "works";
})
app.config(function($stateProvider,$urlRouterProvider,$httpProvider){
$httpProvider.interceptors.push('AuthInter');
$urlRouterProvider.otherwise('/home')
$stateProvider
.state('home',{
controller:'mainController',
url:'/home',
views: {
'main':{
templateUrl: 'templates/home.html',
}
}
})
.state('signUp',{
controller:'mainController',
url:'/signUp',
views: {
'main':{
templateUrl: 'templates/signUp.html',
controller: function($scope,$http,$timeout,$state){
$scope.register = function(){
$scope.serverMsg =false;
$http.post('/signUp', $scope.newUser).then(function(data){
$scope.serverMsg = data.data;
if($scope.serverMsg.success == true){
$timeout(function(){
$state.go('login');
}, 2000);
}
})
}
}
}
}
})
.state('login',{
controller:'mainController',
url:'/login',
views: {
'main':{
templateUrl: 'templates/login.html',
controller: function($scope,$http,$timeout,$state,$window){
$scope.setCurrentUser = function(user){
$scope.currentUser = user;
console.log($scope.currentUser);
}
$scope.serverMsg = false;
$http.get('http://localhost:8080/users').then(function({ data: users }) {
$scope.users = users;
})
}
}
}
})
.state('checkIn',{
controller:'mainController',
url:'/checkIn',
views: {
'main':{
templateUrl: 'templates/checkIn.html',
// resolve: {
// },
controller: function($scope,$http,$state,$window,$timeout){
console.log(demo);
var today = new Date();
var hour = today.getHours();
var minute = today.getMinutes();
var meridianPlaceHolder = today.getHours();
meridianPlaceHolder = AmPm(meridianPlaceHolder);
minute = checkTime(minute);
hour = checkHour(hour);
//Handles Times
function AmPm(i){
if(i < 12){
return "AM";
}
else{
return "PM";
}
}
function checkHour(i){
if (i > 12){
i = i - 12;
};
return i;
}
function checkTime(i) {
if (i < 10) {
i = "0" + i
}; // add zero in front of numbers < 10
return i;
}
//var arrivalTime = document.getElementById("arrivalTime");
//Sets a default input value for the arrivalTime
$scope.arrivalTime = hour + ":" + minute + " " + meridianPlaceHolder;
//arrivalTime.setAttribute("value", hour + ":" + minute + " " + meridianPlaceHolder);
//Checks whether or not the user has chosen a latop
var laptopQuery = false;
$('#yesLaptop').click(function(){
laptopQuery = true
});
$('#noLaptop').click(function(){
laptopQuery = false
});
//Handles the Inputs of the Check In Page
$scope.submit = function(){
$scope.serverMsg = false;
console.log("Submitting Check In...");
//Assigns a Random Laptop
var laptops = ["laptop2","laptop3","laptop4","laptop5","laptop6","laptop7","laptop8","laptop9","laptop10","laptop11","laptop12","laptop13","laptop14","laptop15","laptop16","laptop17","laptop18","laptop19","laptop20","laptop21","laptop22","laptop23","laptop24"];
var laptop = laptops.splice([Math.floor(Math.random()*laptops.length)], 1);
//Retrieves input values
var timeLogArrival = document.getElementById("arrivalTime").value;
var timeLogDepature = document.getElementById("depatureTime").value;
var reasonForVisit = document.getElementById("reasonForVisit").value;
//Logs data, isn't currently working on monogo
console.log("Time of Arrival: " + timeLogArrival);
console.log("Time of Departure: " + timeLogDepature);
console.log("Reason for Visit: " + reasonForVisit);
//Displays whether or not a user checke out a laptop or not
if (laptopQuery){
console.log("Your Laptop: " + laptop);
alert("Your Laptop: " + laptop);
}
else{
console.log("You didn't check out a laptop");
}
// var laptopUpdateQuery = {laptopId:laptop};
// var userQuery = {'name':$scope.currentUser.name};
// user.findOneandUpdate(userQuery,laptopUpdateQuery,function(err,doc){
// err ? console.log(err) : alert("success");
// })
$http.put('/check',$scope.currentUser).then(function(data){
$scope.serverMsg = data.data;
if($scope.serverMsg.success == true){
$timeout(function(){
console.log("user data updated");
$state.go('home');
}, 2000);
}
});
}
}
}
}
});
});
// this is for the phone number
app.directive('phoneInput', function($filter, $browser) {
return {
require: 'ngModel',
link: function($scope, $element, $attrs, ngModelCtrl) {
var listener = function() {
var value = $element.val().replace(/[^0-9]/g, '');
$element.val($filter('tel')(value, false));
};
// This runs when we update the text field
ngModelCtrl.$parsers.push(function(viewValue) {
return viewValue.replace(/[^0-9]/g, '').slice(0,10);
});
// This runs when the model gets updated on the scope directly and keeps our view in sync
ngModelCtrl.$render = function() {
$element.val($filter('tel')(ngModelCtrl.$viewValue, false));
};
$element.bind('change', listener);
$element.bind('keydown', function(event) {
var key = event.keyCode;
// If the keys include the CTRL, SHIFT, ALT, or META keys, or the arrow keys, do nothing.
// This lets us support copy and paste too
if (key == 91 || (15 < key && key < 19) || (37 <= key && key <= 40)){
return;
}
$browser.defer(listener); // Have to do this or changes don't get picked up properly
});
$element.bind('paste cut', function() {
$browser.defer(listener);
});
}
};
});
app.filter('tel', function () {
return function (tel) {
console.log(tel);
if (!tel) { return ''; }
var value = tel.toString().trim().replace(/^\+/, '');
if (value.match(/[^0-9]/)) {
return tel;
}
var country, city, number;
switch (value.length) {
case 1:
case 2:
case 3:
city = value;
break;
default:
city = value.slice(0, 3);
number = value.slice(3);
}
if(number){
if(number.length>3){
number = number.slice(0, 3) + '-' + number.slice(3,7);
}
else{
number = number;
}
return ("(" + city + ") " + number).trim();
}
else{
return "(" + city;
}
};
});
//Javascript for the Date to show in the input field by default
// Time
// controller: function($scope,$http,$timeout,$state,$window){
// $scope.login = function(){
// $scope.serverMsg =false;
// $http.get('mongodb://localhost:27017/cubeData', $scope.user.name).then(function(data){
// $scope.serverMsg = data.data;
// if($scope.serverMsg.success == true){
// $timeout(function(){
// $state.go('checkIn');
// }, 2000);
// }
// });
// }
// }
// }
// }
// })
// $scope.loggingOut = false;
// $scope.logout = function(){
// $window.localStorage.removeItem('token');
// $scope.loggingOut = true;
// $timeout(function () {
// $state.go('signUp');
// }, 3000);
// }

There are a few ways to do this, in descending order of correctness.
First - Create a factory/service/value/constant within the app to hold this shared value and include it everywhere you need to access the value, preferably with a getter/setter for the value.
In the following example, it would be preferable to get the values by including myService and calling myService.getMyObject(), but still
possible to simply use myService.myValue e.g. -
app.service('myService', function() {
var service = {
myValue: 'some value',
myObject: { foo: 'bar' },
getMyObject: function() { return service.myObject; },
setMyObject: function(data) { service.myObject = data; }
};
return service;
});
Second - (This is kind of a hack and not a good practice) is to store the value on the $rootScope. This makes it globally available - in controllers, services, and templates. It's easy to pollute using this method, so option 1 is preferred.
Third - (not recommended) You could do it the way you are trying, but it's not advisable. You'd have to either use the controllerAs syntax defining your controllers and access the value through $scope.main.demo, or without controllerAs, through $scope.$parent.demo <-- this gets ugly and confusing fast, depending on nesting.

Create a service to share data across your application

As #LouisK pointed out, the first way it's the suggested one. I would say also that you can consider the angular value too if you want to share just one single variable, otherwise services are the right way.
app.value('myVar', 'Default Value');
In order to change it:
$provide.decorator('myVar', function ($delegate) { return $delegate + ' and same value more'; });
Then simply inject myVar where you need.

Related

$http.put not updating model

I'm attempting to learn the MEAN stack and learning to use the $http service.
I currently have a global check in place that is suppose to update my Sprints model, which looks like:
var SprintSchema = new Schema({
tasks: [{
type: String,
ref: 'Task'
}],
name: {
type: String
},
start: {
type: Date
},
end: {
type: Date
},
active: Boolean
});
The following controller should update the Sprint model when requested, and when I console.log the variable in my success function, it looks like what I would expect it to pass but it doesn't actually end up updating my model. Below is my code and an example of the console.log.
'use strict';
angular.module('inBucktApp')
.service('VariableService', function () {
// AngularJS will instantiate a singleton by calling "new" on this function
var ticketId = 'noTicketYet';
var ticketAssigneeName = 'noTicketNameYet';
return {
getPropertyId: function () {
return ticketId;
},
getPropertyName: function () {
return ticketAssigneeName;
}
,
setProperty: function(value, valueName) {
ticketId = value;
ticketAssigneeName = valueName;
}
};
})
.run(['$rootScope', '$http', 'socket', 'VariableService', function($rootScope, $http, socket, VariableService) {
$rootScope.sprintStart;
$http.get('/api/sprints').success(function(sprints) {
$rootScope.sprints = sprints.pop();
$rootScope.sprintStart = new Date($rootScope.sprints.start);
$rootScope.sprintEnd = new Date($rootScope.sprints.end);
socket.syncUpdates('sprints', $rootScope.sprints);
$http.get('/api/tasks').success(function(task) {
$rootScope.task = task;
$rootScope.taskPop = _.flatten($rootScope.task);
$rootScope.taskPopAgain = $rootScope.task.pop();
socket.syncUpdates('task', $rootScope.task);
$rootScope.updateTicket = function(){
//Goes through the entire array and check each element based on critera.
var taskIdsToAdd = [];
for(var i = 0; i < $rootScope.taskPop.length; i++){
var taskFind = $rootScope.taskPop[i];
//Logic if ticket is not in the sprint
if ((new Date(taskFind.start) >= $rootScope.sprintStart) && (new Date(taskFind.start) <= $rootScope.sprintEnd)){
taskFind.sprint = true;
taskIdsToAdd.push(taskFind._id);
$rootScope.sprints.tasks.push(taskFind._id);
$http.put("/api/tasks/"+taskFind._id,taskFind).success(function(task){
console.log('Logic 1 Ran!');
console.log($rootScope.sprintStart);
// socket.syncUpdates('taskPopAgain', taskFindPopAgain);
});
$http.put("/api/sprints/"+$rootScope.sprints._id,$rootScope.sprints).success(function(sprints){
console.log('Logic 2 Ran!');
console.log($rootScope.sprintStart);
console.log(sprints)
});
console.log($rootScope.sprints);
} else{
console.log('this doesnt work first');
};
//Logic if ticket is not in the sprint
if (new Date(taskFind.start) < $rootScope.sprintStart || new Date(taskFind.start) > $rootScope.sprintEnd){
taskFind.sprint = false;
$http.put("/api/tasks/"+taskFind._id,taskFind).success(function(task){
console.log(task);
});
}else{
console.log('this doesnt work');
};
}
};
$rootScope.updateTicket();
});
});
}]);
Console.Log of console.log(sprints)
Anyone have any idea what I'm doing incorrect here?
Thanks for the help guys.

AngularJS Jasmine Tests

I've been learning AngularJS for a while now and am finally getting my head around how it works after being a back-end developer for years.
However, I'm having an enormous amount of trouble understanding how unit testing works with Karma + Jasmine.
Every article I read either stops at testing a controller $scope variable for a value or dives so far into the deep end I get lost in the first paragraph.
I'm hoping someone can write a demo test for this controller so I can get my head around how to test controller functions with private variables etc.
financeApp.controller('navController', ['$scope', '$resource', '$cookies', '$location', function ($scope, $resource, $cookies, $location) {
// Set default values
$scope.resultList = [];
$scope.cookieExp = moment().add(3, 'months').toDate();
$scope.dataLoaded = true;
$scope.codesList = [];
// Update watchlist item stock prices
$scope.updateWatchItem = function (items) {
sqlstring = items.join("\",\"");
var financeAPI = $resource('https://query.yahooapis.com/v1/public/yql', {callback: "JSON_CALLBACK" }, {get: {method: "JSONP"}});
financeAPI.get({q: decodeURIComponent('select%20*%20from%20yahoo.finance.quote%20where%20symbol%20in%20(%22' + sqlstring + '%22)'),
format: 'json', env: decodeURIComponent('store%3A%2F%2Fdatatables.org%2Falltableswithkeys')})
.$promise.then(function (response) {
var quotes = response.query.results.quote;
quotes = Array.isArray(quotes) ? quotes : [quotes];
quotes.forEach(function (quote) {
$scope.createWatchItem(quote);
});
}, function (error) {
alert("ERROR: There was an issue accessing the finance API service.");
});
};
// Add a new watchlist item (triggered on button click)
$scope.newWatchItem = function () {
var newcode = $scope.asxcodeinput;
if (newcode == null) {
alert('Please enter a valid ASX equities code...');
return;
}
else if ($scope.codesList.indexOf(newcode + '.AX') > -1) {
alert('You are already tracking ' + newcode.toUpperCase() + '!');
return;
}
$scope.dataLoaded = false;
var financeAPI = $resource('https://query.yahooapis.com/v1/public/yql', {callback: "JSON_CALLBACK" }, {get: {method: "JSONP"}});
financeAPI.get({q: decodeURIComponent('select%20*%20from%20yahoo.finance.quote%20where%20symbol%20in%20(%22' + newcode + '.AX%22)'),
format: 'json', env: decodeURIComponent('store%3A%2F%2Fdatatables.org%2Falltableswithkeys')})
.$promise.then(function (response) {
$scope.dataLoaded = true;
var quote = response.query.results.quote;
if(quote.StockExchange != null) {
$scope.createWatchItem(quote);
$cookies.putObject('codesCookie', $scope.codesList, {expires: $scope.cookieExp});
$location.path('/' + (quote.Symbol).split('.')[0].toUpperCase());
}
else {
alert("Woops! Looks like that stock doesn't exist :(");
}
}, function (error) {
alert("ERROR: There was an issue accessing the finance API service.");
});
$scope.asxcodeinput = "";
};
// Delete a watchlist item (triggered on delete icon click)
$scope.deleteWatchlistItem = function (asxcode) {
$scope.resultList.forEach(function (result, key) {
if(result.Symbol == asxcode) {
$scope.resultList.splice(key, 1);
}
});
$scope.codesList.forEach(function (code, key) {
if(code == asxcode) {
$scope.codesList.splice(key, 1);
}
});
$cookies.putObject('codesCookie', $scope.codesList, {expires: $scope.cookieExp});
$location.path('/');
};
// Add new watchlist item to lists of watched items
$scope.createWatchItem = function (quote) {
$scope.resultList.push(quote);
$scope.codesList.push(quote.Symbol);
};
// Get current page for navigation menu CSS
$scope.isActive = function (location) {
return location === $location.path();
};
// If the cookie is set and not empty, populate the watchlist items with the cookie contents
if($cookies.getObject('codesCookie') && $cookies.getObject('codesCookie').length > 0) {
$scope.updateWatchItem($cookies.getObject('codesCookie'));
}
}]);
Also, if anyone can recommend an easy to read article on unit testing in AngularJS I'd appreciate it.
That is a big lump to start testing with. I suggest looking at the tutorial page REST and Custom Services on the angular site and put the resource stuff in a service.
I suggest viewing some good videos on jasmine at https://www.youtube.com/channel/UC4Avh_hoUNIJ0WL2XpcLkog
I do recommend you view up to and including the one on spies.

Routing using RESOLVE does not wait on complete result to start with second reolve function

Still new to AngularJS , I have following situation...Which I'm looking for a solution ...
When the APP is loaded (before any screen is shown) - I need to load following (in a fixed order as shown in the list):
.properties file and store the properties to a ARRAY
REST service method to get all translations labels to be used in the application
Because the properties file will contain for example connection properties, it's important this properties file is loaded & parsed before proceeding with the app...
Using the $routeProvider I've used following to work with the 'resolve' approach:
// routing
app.config(function($routeProvider) {
$routeProvider
// login
.when('/', {
templateUrl : 'pages/login.html',
controller : 'loginController',
resolve:{
// load properties
loadProperties: function(properties){
return properties.initProperties();
},
// load labels
loadLocalization: function(localize, properties){
console.log(properties.getProperties());
return localize.initLocalizedResources();
}
}
})
// dashboard
.when('/dashboard', {
templateUrl : 'pages/login.html'
})
});
The 'initLocalizedResources' method:
initLocalizedResources: function(){
if (!localize.loadedFromRest){
localize.loading = true;
//$localStorage.restServer = "http://localhost:8084";
// var restServer = properties.getProperty('restServer') + '/WebSDPServiceMobileAPI/i18n/i18nlabels_get/culture/';
var restServer = 'http://localhost:3034';
var restServer = restServer + '/WebSDPServiceMobileAPI/i18n/i18nlabels_get/culture/';
var culture = 'en-gb';
if ($localStorage.language !== undefined)
culture = $localStorage.language.culture;
var restCall = restServer + culture;
logMessage(' - Localize - callRestServer called - : ' + restCall);
return $http.get(restCall)
.success(localize.successCallback)
.error(function(data, status){
// set the flag to keep from looping in init
localize.loadedFromRest = false;
localize.loading = false;
});
}
},
The 'properties' service:
app.factory('properties', function($http){
var arrProperties = [];
return {
getProperties: function(){
return arrProperties;
},
getProperty: function(key){
return arrProperties[key];
},
addProperty: function(key, value){
console.log('add property : ' + key + ' - ' + value);
arrProperties[key] = value;
},
initProperties: function(){
return $http.get('serviceapp.properties').then(function (response) {
var props = response.data.split("\n");
for (var i = 0, len = props.length; i < len; i++) {
var value = props[i].split("=");
arrProperties[value[0]] = value[1];
}
console.log(arrProperties);
});
}
};
});
But what I notice is that the order of the Resolve is not the correct order...
When logging the properties inside the initLocalizedResources method, they are still []... While logging the 'properties' inside the loginControllerthey are correctly filled with data... But at a stage too far...
What I need to accomplish is to load the properties before the localization labels (REST)...
My ideas of workaround:
Add an extra route for loading the properties, and when completing navigating to the second route, where it will load the localization, then continue to the /login route
Manually bootstrap the AngularJS application after loading & parsing the properties
As mentioned, these feel and are workarounds, ...
Is there anybody with any other ideas / tips or any help?
Thanks
I believe you can do it like this:
resolve:{
// load properties
loadProperties: function(properties){
return properties.initProperties();
},
// load labels
loadLocalization: function(localize, properties, loadProperties){
console.log(properties.getProperties());
return localize.initLocalizedResources();
}
}
Notice, how the second resolve is dependent on the loadProperties resolve.
https://medium.com/opinionated-angularjs/advanced-routing-and-resolves-a2fcbf874a1c

Angular JS Handle controller Events

I have an application having a lot of things to save in cascade, imaging a normal master - detail view.
In this view I have a "Save All" Button that save each row in an iteration, triggering jQuery custom events, to serialize the saving operations and prevent the generation an uncontrolled queue of requests.
Each time a row is saved, the program decrement the counter and launch the save of the new row.
Everything ends when there where no rows to save (counter = 0).
This is a code snippet doing this:
var save_counter = -1;
// Creates a counter and save content header when finished to save rows.
var updCounter = function(evt){
// Update Counter
save_counter--;
// Register updates When there are not rows to skip
if ((save_counter===0)
|| (save_counter===0 && edit_status == "modified") ){
console.log('Persist Master');
$(document).trigger('save_ok');
}
};
saveRows = $(form_sel);
// Reset Save Counter
save_counter = saveRows.length;
// Iterate through lines
saveRows.each(function(idx){
var form = $(this);
// Execute Uptade Counter once
form.one(update_counter, updCounter);
// Per each performed save, decrese save counter
form.trigger('submit');
});
Now I'm migrating some critical application modules, using angular but I have no idea to do that.
There is a best practice to perform a batch request call?
Is it a good idea to use $scope variables and $watch, using something like this?
var RowController = angular.controller('RowController', function($scope, $http){
$scope.rows = [
{id : 1, title : 'lorem ipsum'}
, {id : 2, title : 'dolor sit amet'}
, {id : 3, title : 'consectetuer adipiscing elit'}
];
// Counter Index
$scope.save_counter = -1;
// "Trigger" the row saving, changing the counter value
$scope.saveAll = function () {
$scope.save_counter = 0;
};
// Watch the counter and perform the saving
$scope.$watch('save_counter', function(
// Save the current index row
if ($scope.save_counter >= 0
&& $scope.save_counter < $scope.rows.length) {
$http({
url : '/row/' + $scope.rows[$scope.save_counter].id,
data: $scope.rows[$scope.save_counter]
}).success(function(data){
// Update the counter ...
$scope.save_counter ++;
}).error(function(err){
// ... even on error
$scope.save_counter ++;
});
};
));
});
The best approach is to use a service with promises ($q).
Here's an example:
app.factory('RowService', function($http, $q) {
return {
saveRow: function(row) {
return $http({
url: '/row/' + row.id,
data: row
});
},
saveAll: function(rows) {
var deferred = $q.defer();
var firstRow = rows.shift();
var self = this;
// prepare all the saveRow() calls
var calls = [];
angular.forEach(rows, function(row) {
calls.push(function() {
return self.saveRow(row);
});
});
// setup the saveRow() calls sequence
var result = this.saveRow(firstRow);
angular.forEach(calls, function(call) {
result = result.then(call);
});
// when everything has finished
result.then(function() {
deferred.resolve();
}, function() {
deferred.reject();
})
return deferred.promise;
}
}
});
And on your controller:
app.controller('RowController', function($scope, RowService) {
...
$scope.saveAll = function() {
// $scope.rows.slice(0) is to make a copy of the array
RowService.saveAll($scope.rows.slice(0)).then(
function() {
// success
},
function() {
// error
})
};
});
Check this plunker for an example.

AngularJS : factory to return data from a php service using $http

I'm newbie to js and this is my first question in stackoverflow as well. So any comment or act of downgrading is understandable.
This is the angular-js-flowchart project on github.
This is another stackoverflow topic that teachs how to use factory as a data getter involving $http.
My need is to generate data for the chart by using an Angular factory that returns a $http function. The $http talks to a php service that retrieve data from database. I have tested the service using jsonlint and its working fine. The directory of service is checked, relatively to the html file.
I copied the "factory" code from another stackoverflow question and applied to app.js in the angularjs-flowchart Github project.
The problem is that the Chrome console keeps throwing an error that I can not understand. Data is not retrieved. The error on console is "TypeError: Cannot read property 'getData' of undefined"
This is the modified-by-me app.js:
//
// Define the 'app' module.
//
angular.module('app', ['flowChart', ])
//
// Simple service to create a prompt.
//
.factory('prompt', function () {
/* Uncomment the following to test that the prompt service is working as expected.
return function () {
return "Test!";
}
*/
// Return the browsers prompt function.
return prompt;
})
//
// Application controller.
//
.controller('AppCtrl', ['$scope', 'prompt', function AppCtrl ($scope, prompt, dataFactory) {
//
// Code for the delete key.
//
var deleteKeyCode = 46;
//
// Code for control key.
//
var ctrlKeyCode = 65;
//
// Set to true when the ctrl key is down.
//
var ctrlDown = false;
//
// Code for A key.
//
var aKeyCode = 17;
//
// Code for esc key.
//
var escKeyCode = 27;
//
// Selects the next node id.
//
var nextNodeID = 10;
//
// Event handler for key-down on the flowchart.
//
$scope.keyDown = function (evt) {
if (evt.keyCode === ctrlKeyCode) {
ctrlDown = true;
evt.stopPropagation();
evt.preventDefault();
}
};
//
// Event handler for key-up on the flowchart.
//
$scope.keyUp = function (evt) {
if (evt.keyCode === deleteKeyCode) {
//
// Delete key.
//
$scope.chartViewModel.deleteSelected();
}
if (evt.keyCode == aKeyCode && ctrlDown) {
//
// Ctrl + A
//
$scope.chartViewModel.selectAll();
}
if (evt.keyCode == escKeyCode) {
// Escape.
$scope.chartViewModel.deselectAll();
}
if (evt.keyCode === ctrlKeyCode) {
ctrlDown = false;
evt.stopPropagation();
evt.preventDefault();
}
};
//
// Add a new node to the chart.
//
$scope.addNewNode = function () {
var nodeName = prompt("Enter a task name:", "New Task");
if (!nodeName) {
return;
}
//
// Template for a new node.
//
var newNodeDataModel = {
name: nodeName,
id: nextNodeID++,
x: 0,
y: 0,
inputConnectors: [
{
name: "Pre"
}
],
outputConnectors: [
{
name: "Sub"
}
],
};
$scope.chartViewModel.addNode(newNodeDataModel);
};
//
// Add an input connector to selected nodes.
//
$scope.addNewInputConnector = function () {
var connectorName = prompt("Enter a connector name:", "New connector");
if (!connectorName) {
return;
}
var selectedNodes = $scope.chartViewModel.getSelectedNodes();
for (var i = 0; i < selectedNodes.length; ++i) {
var node = selectedNodes[i];
node.addInputConnector({
name: connectorName,
});
}
};
//
// Add an output connector to selected nodes.
//
$scope.addNewOutputConnector = function () {
var connectorName = prompt("Enter a connector name:", "New connector");
if (!connectorName) {
return;
}
var selectedNodes = $scope.chartViewModel.getSelectedNodes();
for (var i = 0; i < selectedNodes.length; ++i) {
var node = selectedNodes[i];
node.addOutputConnector({
name: connectorName,
});
}
};
//
// Delete selected nodes and connections.
//
$scope.deleteSelected = function () {
$scope.chartViewModel.deleteSelected();
};
//
// Setup the data-model for the chart.
//
var chartDataModel = {};
var handleSuccess = function(data, status){
chartDataModel = data;
console.log(chartDataModel);
};
dataFactory.getData().success(handleSuccess);
//
// Create the view-model for the chart and attach to the scope.
//
$scope.chartViewModel = new flowchart.ChartViewModel(chartDataModel);
}])
.factory('dataFactory', function($http){
return {
getData : function(){
return $http.post("chart-data-retrieve.php");
}
};
});
Basically, what i added but doesn't work is
// Setup the data-model for the chart.
//
var chartDataModel = {};
var handleSuccess = function(data, status){
chartDataModel = data;
console.log(chartDataModel);
};
dataFactory.getData().success(handleSuccess);
and
.factory('dataFactory', function($http){
return {
getData : function(){
return $http.post("chart-data-retrieve.php");
}
};
});
Please help, thanks.
I tried to set the chartViewModel of the $scope directly inside the service call, so the variable chartDataModel becomes redundant. And it works.
// Create the view-model for the chart and attach to the scope.
//
myService.then(function(data) {
$scope.chartViewModel = new flowchart.ChartViewModel(data);
});
I tried to return a promise, not a $http from the factory. It works now. The controller can now use the service to retrieve data. However I still could not set the controller's variable to the data retrieved.
The following is the code:
.factory('myService', function($http, $q) {
//this runs the first time the service is injected
//this creates the service
var deferred = $q.defer();
$http.get('chart-data-retrieve.php').then(function(resp) {
deferred.resolve(resp.data);
});
return deferred.promise;
})
And the code inside controller:
var chartDataModel = {};
//get data from myService factory
myService.then(function(data) {
alert(data);
chartDataModel = data;
});
Currently, the alert() show me the data already. However, the variable chartDataModel is still unset.

Categories