How to wait till the execution of angular js controller is completed - angularjs

I have created two angular js services as given below:-
var app = angular.module("myApp",[]);
app.service('myServices',function(){
var officeMasterData;
//In this function I fetch the sharepoint list as try to store the data in this service.
this.getDataFromSharepoint = function(){
var deferred = $.Deferred();
var context = new SP.ClientContext('siteUrl');
.......
context.executeQueryAsync(function(){
var listItemEnumerator = colListItem.getEnumerator();
officeMasterData = listItemEnumerator;
return deferredA.resolve(listItemEnumerator);
},function(error){
return deferred.reject(error)
});
return deferred.promise();
}
// Another function in the service to get the data which is already stored from the function above.
this.getDataSaved = function(){
return officeMasterData;
}
});
Then create the second service for another purpose.
Following the code for the second service that I have created.
Here I try to store the email Id of the current Logged in user.
app.service('userServices',function(){
var userArray = {};
this.getCurrentUserDetails = function(){
var deferred = $.Deferred();
var context = new SP.ClientContext.get_current();
var web = context.get_web();
currentUser = web.get_currentUser();
context.load(currentUser);
context.executeQueryAsync(function(){
userArray['id'] = currentUser.get_email();
return deferred.resolve(userArray['id']);
},function(error){
return deferred.reject(error);
});
return deferred.promise();
}
this.getOtherDetails = function(a){
//gets data from another list based on the email Id that has been generated and appends new data to the array.
..........
context.executeQueryAsync(function(){
userArray['First'] = 'Some';
userArray['Last'] = 'thing';
return deferred.resolve(userArray);
},function(error){
return deferred.reject(error);
});
return deferred.promise();
}
this.getMyDetails = function(){
return userArray;
}
});
Then I created two controllers that would consume the services as below:-
angular.module('myApp').controller('userController',userController);
userController.$inject = ['$scope','userServices'];
function userController($scope,userServices){
var alreadySavedData = userServices.getMyDetails();
if(alreadySavedData['First_Name'] === undefined){
var getCurrent = userServices.getCurrentUserDetails();
var getFurtherCurrent = getCurrent.then(function(res){
return userServices.getOtherDetails(res)
});
getFurtherCurrent.then(function(resArr){
$scope.UserDetails = resArr;
$scope.$apply();
});
}else{
var getCurrent = userServices.getMyDetails();
$scope.getCurrent = resArr;
$scope.$apply();
}
}
Here is the code of another controller.
angular.module('myApp').controller('myTController',myTController);
myTController.$inject = ['$scope','myServices','userServices'];
function mTController($scope,myServices,userServices){
var userDetails = userServices.getMyDetails();
var myData = myServices.getDataFromSharepoint();
}
Here is the HTML code for the reference:-
<body data-ng-app="myApp">
<div id="main_header" ng-controller="userController as user">
<div id="header_inner1">
<div class="mobile_menu">
<div class="ham1"></div>
<div class="ham2"></div>
<div class="ham3"></div>
</div>
<div id="logo">
<img src="images/myImg.png" alt="imgLogo"/>
</div>
</div>
</div>
<div ng-controller="mTController" id="myTC" style="display:none;margin-top:10px;">
<table>
<thead>
<tr>
<th>ID</th>
<th>First Name</th>
<th>Last Name</th>
<th>Company Name</th>
</tr>
</thead>
<tr ng-repeat="tr in offices">
<td data-ng-cloak>{{tr.ID}}</td>
<td data-ng-cloak>{{tr.First_x0020_Name}}</td>
<td data-ng-cloak>{{tr.Last_x0020_Name}}</td>
<td data-ng-cloak>{{tr.Company_x0020_Name}}</td>
</tr>
</table>
</div>
<script src="js/userController.js"></script>
<script src="js/officeController.js"></script>
</body>
Here the problem is that my mTController gets executed before userController
Here the I want to execute the mTController after userController is completely executed because the data passing from the userController will be used in mTController for further operations and that's not happening.
What could be the problem?
I have googled around but I couldn't found any solution.
Any help would be appreciable.

Related

Binding scope object to factory object

I am connecting to a websocket feed in a factory, which gives me real time bitcoin price data.
I define service.prices as an object in websocketFactory, and set wsvm.prices = websocketFactory.prices in the controller.
The wsvm.prices.btc property is not updating in the view, but is logging correctly in console.
code:
factory
app.factory('websocketFactory', ['$http', function($http) {
var service = {}
service.prices = {
"btc": 0
}
service.gdax = function() {
const socket = new WebSocket('wss://ws-feed.gdax.com')
var message = {
"type": "subscribe",
"channels": [{
"name": "ticker",
"product_ids": [
"BTC-USD"
]
}, ]
}
socket.addEventListener('open', function(event) {
socket.send(JSON.stringify(message));
})
// Listen for messages
socket.addEventListener('message', function(event) {
var dataObj = JSON.parse(event.data)
if (dataObj.price) {
console.log(dataObj.price) //logging real time data
service.prices.btc = dataObj.price //this should be updating the view
}
});
}
return service
}])
controller
app.controller('WebsocketController', WebsocketController)
WebsocketController.$inject = ['$scope', 'websocketFactory']
function WebsocketController($scope, websocketFactory) {
var wsvm = this
wsvm.prices = websocketFactory.prices
websocketFactory.gdax()
}
view
<div ng-controller="PortfolioController as vm">
<div class="row">
<div class="col-sm-6">
<h2 style="text-align: center;">Account Balances</h2>
</div>
<div class="col-sm-6">
<table class="table">
<thead>
<tr>
<td>24h Change</td>
<td>Total Val USD</td>
<td>BTC Price</td>
</tr>
</thead>
<tbody>
<tr>
<td ng-class="{change_loss: vm.totals.change_24h_usd < 0, change_win: vm.totals.change_24h_usd > 0}"><b>{{vm.totals.change_24h_usd | currency}}</b></td>
<td><b>{{vm.totals.total_usd | currency}}</b></td>
<td ng-controller="WebsocketController as wsvm">{{wsvm.prices.btc}}</td>
</tr>
</tbody>
</table>
</div>
</div>
How to correctly bind factory to controller for real time data?
Changing scope in the socket listener is outside of angular context. Whenever that happens angular needs to be notified to run a digest to update view
Try the following:
app.factory('websocketFactory', ['$http', '$rootScope', function($http, $rootScope) {
......
socket.addEventListener('message', function(event) {
var dataObj = JSON.parse(event.data)
if (dataObj.price) {
console.log(dataObj.price) //logging real time data
$rootScope.$apply(function(){
service.prices.btc = dataObj.price //this should be updating the view
});
}
});
});
I also suggest you look for an angular socket module that will take care of all of this for you internally

Angular Delete row from table using angular services

I am trying to delete a table row using angular services, but unfortunately I don't know how to do that. I have to do that using services because I am using several services with the same control.
<script>
var myApp = angular.module("myApp", []);
myApp.service('allCurrentSettingsService', ['$http', '$q', function ($http, $q) {
var allSettings = null;
this.getList = function () {
var def = $q.defer()
if (allSettings) {
def.resolve(allSettings);
} else {
$http.post('GetAllCurrentSettings')
.then(function (response) {
var response = $.parseJSON(response.data)
allSettings = response;
def.resolve(allSettings);
});
}
return def.promise;
}
}]);
myApp.controller('myController', ['$scope', 'allCurrentSettingsService',
function ($scope, allCurrentSettingsService) {
$scope.allSettings = '';
allCurrentSettingsService.getList().then(function (value) {
$scope.allSettings = value;
});
}
]);
</script>'
And this is my HTML:
`
<div ng-controller="myController">
<table border="1">
<tr ng-repeat="setting in allSettings">
<td><input id="Button1" type="button" value="Delete" data-ng-click="DeleteRow(rowValue)" /></td>
<td class="hidden">{{setting.SettingID}}</td>
<td>{{setting.CompanyName}}</td>
<td>{{setting.CustomerName}}</td>
<td>{{setting.DocumentName}}</td>
</tr>
</table>
</div>
`
Delete method from controller:
[HttpPost]
public static void DeleteRecord(int settingID)
{
try
{
using (SqlConnection conn = new SqlConnection(connStringApps))
{
conn.Open();
using (SqlCommand command = new SqlCommand("DeleteCurrentRecord", conn))
{
command.CommandType = System.Data.CommandType.StoredProcedure;
command.Parameters.Add("#SettingId", SqlDbType.VarChar).Value = settingID;
command.ExecuteNonQuery();
command.Parameters.Clear();
}
conn.Close();
}
}
catch (Exception ex)
{
Console.Write(ex.ToString());
}
}
Answer Updated
I do not recommend to remove a row from your service, it's better if you do that from controller, but for figure out how can remove a row from service see the example.
To Remove From Controller you just convert the service codes as controller like what you see in sample.
var app = angular.module("app", []);
app.controller("ctrl", function ($scope, service) {
$scope.data = [
{ name: "a" },
{ name: "b" }
];
$scope.deleteRow = function (row) {
$scope.data = service.removeRow(row, $scope.data);
}
$scope.deleteFromController = function (row) {
var indexOf = $scope.data.indexOf(row);
$scope.data.splice(indexOf, 1);
}
});
app.service("service", function ($rootScope) {
this.removeRow = function (row, data) {
var indexOf = data.indexOf(row);
data.splice(indexOf, 1);
return data;
}
});
<!DOCTYPE html>
<html ng-app="app" ng-controller="ctrl">
<head>
<title></title>
</head>
<body>
<h5>click on rows: delete from service</h5>
<table>
<tr ng-repeat="row in data" ng-click="deleteRow(row)">
<td>{{row.name}}</td>
</tr>
</table>
<h5>click on rows: delete from controller</h5>
<table>
<tr ng-repeat="row in data" ng-click="deleteFromController(row)">
<td>{{row.name}}</td>
</tr>
</table>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
</body>
</html>
From the front end if you want to remove get the index of setting which you want to remove and then use splice.
in the html there has to be an button which initiate the delete operation
your html should be, a rough idea
<tr ng-repeat ="setting in allSettings">
<td>{{setting.SettingID}}</td>
<!-- other items which you wnted to display-->
<!-- put one button for delete and use $index to track the index of item to be removed-->
<td><button ng-click="removeRow($index)">Remove Row</button></td>
</tr>
your controller>>
$scope.removeRoe = function(index){
//splice will remove the setting row and it will get reflected n the view
$scope.allSettings.splice(index,1);
}
FYI
You need not use service, the removing part has to be done in controller. If you need to hit a backend service(post or delete request) that removes the setting then you need to use angular service

Angularjs Service does not work

I define a Service to share a variable between two controllers, but when i set the variable in a controller and then get this from another controller it does not get the correct value , this is the service:
App.service("ProductService", function () {
var productTotalCount = {};
return {
getproductTotalCount: function () {
return productTotalCount;
},
setproductTotalCount: function (value) {
productTotalCount = value;
}
}
});
and this is the controller which i set productTotalCount:
App.controller("ProductController", function ($scope, $http, $rootScope, ProductService) {
$scope.GetAllProducts = $http.get("GetAllProductsInformation").success(function (data) {
$rootScope.Products = data.Data;
ProductService.setproductTotalCount(data.TotalCount); // i set productTotalCount here and it's value became 19
});
$scope.editProduct = function (data) {
$scope.model = data;
$rootScope.$broadcast('modalFire', data)
}
});
and when i get the productTotalCount in this controller it return object instead of 19 :
App.controller('Pagination', function ($scope, ProductService) {
debugger;
$scope.totalItems = ProductService.getproductTotalCount(); // it should return 19 but return object!!
$scope.currentPage = 1;
$scope.itemPerPage = 8;
});
what is the problem?
EDIT: this is the html, it may help :
<div ng-controller="ProductController" ng-init="GetAllProducts()">
<div class="row" style="margin-top:90px" ng-show="!ShowGrid">
<article class="widget">
<header class="widget__header">
<div class="widget__title">
<i class="pe-7s-menu"></i><h3>ProductList</h3>
</div>
<div class="widget__config">
<i class="pe-7f-refresh"></i>
<i class="pe-7s-close"></i>
</div>
</header>
<div class="widget__content table-responsive">
<table class="table table-striped media-table">
<thead style="background-color:rgba(33, 25, 36,0.1)">
<tr>
<th style="width:40%">edit</th>
<th style="width:30%">Price</th>
<th style="width:30%">ProductName</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="product in Products">
#*<td>{{product.ProductDescription}}</td>*#
<td>
<input class="btn btn-default" style="padding: 14px;background: rgba(0, 0, 0, 0.2)" type="submit" value="Edit" ng-click="editProduct(product)" />
</td>
<td>{{product.Price}}</td>
<td>{{product.ProductName}}</td>
</tr>
</tbody>
</table>
</div>
</article>
</div>
</div>
<div ng-controller="Pagination">
<pagination total-items="totalItems" ng-change="pageChanged()" previous-text="Before" next-text="Next" first-text="First"
last-text="Last" ng-model="currentPage" items-per-page="itemPerPage" max-size="maxSize" class="pagination-sm" boundary-links="true"></pagination>
</div>
From the controller names, I bet the Pagination and ProductController controllers are both instantiated more or less at the same time, BEFORE invoking the .setproductTotalCount() method. If that is the case, then because you are treating the productTotalCount variable as a primitive type (instead of an object) after setting it, the changes do not get reflected between the controllers.
Try the following:
// Change the service to:
App.service("ProductService", function () {
var productTotalCount = {};
return {
getproductTotalCount: function () {
return productTotalCount;
},
setproductTotalCount: function (value) {
productTotalCount.value = value;
}
}
});
// In Pagination controller:
App.controller('Pagination', function ($scope, ProductService) {
debugger;
$scope.totalItems = ProductService.getproductTotalCount(); // this will still be an empty object initially, but when the value is updated in the service, the $scope.totalItems will also be updated
$scope.currentPage = 1;
$scope.itemPerPage = 8;
// this should confirm that changes are being propagated.
$scope.$watch('totalItems', function(newVal) {
console.log('totalItems updated. New Value:', newVal);
});
// NOTE: Keep in mind that the real productTotalCount will be stored as $scope.totalItems.value;
});
---- EDIT ----
Per your comment below, it proves that the solution above DOES work. To prove it, change:
$scope.$watch('totalItems', function(newVal) {
console.log('totalItems updated. New Value:', newVal);
});
to
$scope.$watch('totalItems', function(newVal) {
console.log('totalItems updated. New Value:', newVal);
console.log($scope.totalItems);
});
At that point, you should see that $scope.totalItems has been updated to:
{ value: 19 };
The issue may be how you're declaring your variable in your service. Because it's a local variable in the function rather than returned object, I believe it will be creating a new variable for each time you inject the service as a dependency. Try making the variable a member of the returned object. E.g.
App.service("ProductService", function () {
return {
productTotalCount: 0,
getproductTotalCount: function () {
return this.productTotalCount;
},
setproductTotalCount: function (value) {
this.productTotalCount = value;
}
}
});

MEAN Stack: Count and show the Sum of Values via AngularJS

Hi I'm a beginner with the MEAN Stack and currently stuck with a logical challenge.
I know how to get the count of elements of my table with {{element.length}} in HTML but I need to get the total sum of a given value.
Thanks for your help in advance!
HTML:
<div class="jumbotron text-center">
<h1>Volume <span class="label label-info">{{getTotal()}} </span></h1>
</div>
<div class="text-center" >
<table class="table" >
<thead>
<tr>
<th>Drink</th>
<th>Volume</th>
<th>Date</th>
<th>Comment</th>
<th>Action</th>
</tr>
</thead>
<tbody ng-repeat="drink in drinks">
<tr>
<td>{{drink.text}}</td>
<td>{{drink.volume}} Liter</td>
<td>{{drink.time}}</td>
<td>{{drink.comment}}</td>
<td><button type="submit" class="btn btn-primary btn-sm"
ng-click="deleteDrink(drink._id)">delete</button></td>
</tr>
</tbody>
</table>
</div>'
Model:
var mongoose = require('mongoose');
var Schema =new mongoose.Schema({
text : {type : String, default: ''},
volume: {type: Number, default: null},
zeit: {type: Date, default:Date.now},
comment: {type: String}
});
module.exports = mongoose.model('mongoose', Schema);'
Controller:
angular.module('drinkController', [])
// inject the drink service factory into our controller
.controller('mainController', ['$scope','$http','Drinks', function($scope, $http, Drinks) {
$scope.formData = {};
$scope.loading = true;
// GET =====================================================================
// when landing on the page, get all drinks and show them
// use the service to get all the drinks
Drinks.get()
.success(function(data) {
$scope.drinks = data;
$scope.loading = false;
});
// CREATE ==================================================================
// when submitting the add form, send the text to the node API
$scope.createDrink = function() {
// validate the formData to make sure that something is there
// if form is empty, nothing will happen
if ($scope.formData.text != undefined) {
$scope.loading = true;
// call the create function from our service (returns a promise object)
Drinks.create($scope.formData)
// if successful creation, call our get function to get all the new drinks
.success(function(data) {
$scope.loading = false;
$scope.formData = {}; // clear the form so our user is ready to enter another
$scope.drinks = data; // assign our new list of drinks
});
}
}
//Problem Function!! I don't know how to read desired values
$scope.getTotal=function(){
var total=0;
for (var i=0; i <$scope.drinks; i++){
var sum= $scope.drinks.volume[i]; //??
total= sum ; //?
}
return total;
}
// DELETE ==================================================================
// delete a todo after checking it
$scope.deleteDrink = function(id) {
$scope.loading = true;
Drinks.delete(id)
// if successful creation, call our get function to get all the new todos
.success(function(data) {
$scope.loading = false;
$scope.drinks = data; // assign our new list of todos
});
};
}]);
So I have at /api/drinks
[{"_id":"555c23943e0bf3fc403864c3",
"comment":"Yummie",
"__v":0,
"time":"2015-05-20T06:03:17.340Z",
"**volume":2**,
"text":"Coke"},
{"_id":"555c239d3e0bf3fc403864c4",
"comment":"Mooh!",
"__v":0,
"time":"2015-05-20T06:03:17.340Z",
**"volume"**:1,
"text":"Milk"}
]
In my HTML I need a Display of the Value of all Volume Entries, so it would be 3.
This should work:
$scope.getTotal=function(){
var total=0;
for (var i=0; i <$scope.drinks.length; i++){
total += $scope.drinks[i].volume;
}
return total;
}

ng table with data from http request

Does anyone have a decent example with ng-table loading data upon a success callback from http service?
this.getData = function(){
tmp = this;
tmp.loading = true;
$http.post('/fetch',
$.param({
service_request: JSON.stringify(this.session)
}
)).success(function(data) {
tmp.loading = false;
tmp.tableData = data;
});
};
I would like to build the table from the tableData variable.
Thanks
I think this is one way of doing it.
Create a service to get the table data (I just picked the code from your :
app.factory('getTableData', function($http) {
return {
getData: function(session){
return $http.post('/fetch',
{
service_request: session
}))
}
}
})
Then you inject the service in your controller:
app.controller('DemoCtrl', function(getTableData, $scope, $window) {
$scope.loadTable = function(){
getTableData.getData(JSON.stringify($window.session)) //not sure where you have the session variable stored.
.sucess(function(data){
$scope.tableData = data;
})
.error(function(){
//do something
})
}
})
The HTML should be pretty straightforward:
<button ng-click="loadTable()">Load Table</button>
<table ng-table class="table">
<tr ng-repeat="row in tableData">
<td data-title="'Property1'">{{row.Property1}}</td>
<td data-title="'Property2'">{{row.Property2}}</td>
</tr>
</table>

Resources