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
Related
I trying to pass a value from controller1 to controller2 using factory on ng-click, now i have added routing
var app = angular.module("myApp", ['ui.router']);
app.config(function ($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise('/home');
$stateProvider
.state('ShowData', {
url: '/ShowData',
templateUrl: '../Pages/Show.html'
})
.state('EditData', {
url: '/EditData',
controller:'Editctrl',
templateUrl: '../Pages/Edit.html'
})
});
app.controller('Controller1', function ($scope, $http, Phyfactory) {
//Here I am calling a factory
$scope.open = function (name) {
var message = name;
console.log('Hcpname', message);
Phyfactory.set(message);
$location.url('/EditData');
// this is my second controller
app.controller('Editctrl', function ($scope, Phyfactory) {
alert('cntrl2');
$scope.fks = Phyfactory.get();
});
I want to bind this value to textbox
<div ng-controller="Controller2">
Name: <input type="text" ng-model="fks" />
</div>
//this is my factory
app.factory("Phyfactory", function () {
var phyname = {};
function set(data) {
phyname = data;
alert('Inside set :' + phyname);
}
function get() {
alert('Inside get :' + Object.values(phyname));
return phyname;
}
return {
set: set,get:get
}
})
Adding HTML part for controller1 as requested, i am calling ng-click inside td
<div ng-app="myApp" ng-controller="controller1"
<table class="wtable">
<tr>
<th class="wth">
A
</th>
<th class="wth">
B
</th>
</tr>
<tr ng-repeat="tab in Phyperform | filter:search.view_nm|filter:search.time_period|filter:search.team_nm">
<td class="wtd" ><a ng-click="open(tab.A)"> {{tab.A}} </a> </td>
<td class="wtd"> {{tab.B}} </td>
</tr>
</table>
Value is not passing to controller2 and not redirecting as well.
Any idea?
window.location.href
will redirect to out of the app, you must use routing with $location.
of course a better way to pass data between controllers is using event!
using event like below :
this is event receiver in controller 2:
$scope.$on('myCustomEvent', function (event, data) {
console.log(data); // 'Data to send'
});
and this is the sender event in controller 1:
$scope.$emit('myCustomEvent', 'Data to send');
Credit goes to this post "Sharing Data between pages in AngularJS returning empty"
I able to do using sessionStorage.
Unable to bind the table with data i.e. collected from service.
Controller code is as:
app.controller('outletTypeController', ['$scope', '$location', '$timeout', 'outletTypesService', '$uibModal', 'NgTableParams', '$q', '$log',
function ($scope, $location, $timeout, outletTypesService, $uibModal, NgTableParams, $q, $log) {
$scope.message = "";
$scope.animationsEnabled = true;
$scope.outletTypes = [];
//To Load Outlet Types in same controller
$scope.LoadOutletTypes = function () {
outletTypesService.getOutletTypes().then(function (results) {
$scope.outletTypes = results.data.Result;
}, function (error) {
var errors = [];
if (response.data != null) {
for (var key in response.data.modelState) {
for (var i = 0; i < response.data.modelState[key].length; i++) {
errors.push(response.data.modelState[key][i]);
}
}
}
$scope.message = "Failed to load data due to:" + errors.join(' ');
});
};
//To Bind OutletType With Options in same controller
$scope.outletTypeWithOptions = function () {
//to set outletTypes
$scope.LoadOutletTypes();
var initialParams = {
count: 2 // initial page size
};
var initialSettings = {
// page size buttons (right set of buttons in demo)
counts: [10, 50, 100],
// determines the pager buttons (left set of buttons in demo)
paginationMaxBlocks: 5,
paginationMinBlocks: 1,
dataset: $scope.outletTypes
};
return new NgTableParams(initialParams, initialSettings);
};
and HTML View Code is as:
<div id="body" ng-controller="outletTypeController">
<table ng-table="outletTypeWithOptions" class="table table-striped" show-filter="true" cellspacing="0" width="100%">
<tr data-ng-repeat="type in $data">
<td title="'Logo'" class="text-center">
<div class="logoImg">
<img src="images/halalpalc.png" width="30" />
</div>
</td>
<td title="'Outlet Type'" filter="{ OTypeName: 'text'}" sortable="'OTypeName'">
{{ type.OTypeName }}
</td>
<td title="'Icon Rated'">I R</td>
<td title="'Icon Unrated'">I U</td>
<td title="'Status'" class="text-center status">
{{ type.IsActive}}
</td>
<td title="'Action'" class="text-center">
<!--<a href="#" class="editAction" data-toggle="modal" data-target="#myModal" title="Edit">
<img src="images/SVG_icons/edit_action.svg" />
</a>-->
<button data-ng-click="open()" class="btn btn-warning">Edit</button>
<!--<img src="images/SVG_icons/close_action.svg" />-->
</td>
</tr>
</table>
</div>
But unable to bind the data, However I try to bind it with Static Data it's properly working.
Here $scope.LoadOutletTypes is an async method call, which will asynchronously populate $scope.outletTypes with results. Rest of the code after LoadOutletTypes method call won't wait for result instead proceeds for execution, which will populate dataset in initialSettings object with null value(If it was unable to load the outlet types in time. But this will work for static data).
Try the below code..
$scope.LoadOutletTypes = function () {
outletTypesService.getOutletTypes().then(function (results) {
$scope.outletTypes = results.data.Result;
$scope.setOutletTypeWithOptions();
}, function (error) {
var errors = [];
if (response.data != null) {
for (var key in response.data.modelState) {
for (var i = 0; i < response.data.modelState[key].length; i++) {
errors.push(response.data.modelState[key][i]);
}
}
}
$scope.message = "Failed to load data due to:" + errors.join(' ');
});
};
$scope.setOutletTypeWithOptions = function () {
var initialParams = {
count: 2 // initial page size
};
var initialSettings = {
// page size buttons (right set of buttons in demo)
counts: [10, 50, 100],
// determines the pager buttons (left set of buttons in demo)
paginationMaxBlocks: 5,
paginationMinBlocks: 1,
dataset: $scope.outletTypes
};
$scope.NgTableParams = new NgTableParams(initialParams, initialSettings);
};
<div id="body" ng-controller="outletTypeController">
<table ng-table="NgTableParams" ng-init="LoadOutletTypes()" class="table table-striped" show-filter="true" cellspacing="0" width="100%">
<tr data-ng-repeat="type in $data">....
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;
}
}
});
Initially, I am showing all the users name in the table. Once the user selected any one of the name, I call the LoadData method with the selected user as the parameter. I am changing the url #/Trades/User/User1 and append the details under the User1. My requirement is 1) In the LoadData method, I want to change the url to as #/Trades/User/User1 or #/Trades/User/User2 based on the selection 2) It should update the data and reflect in view, but it should not reload the controller.
HTML
<div ng-app="myApp" ng-controller="myCtrl">
<table>
<tr ng-repeat-start="val in data.Titles" class="h" ng-click="LoadData(val.title)">
<td colspan="2" ng-hide="val.title == undefined">{{val.title}}</td>
</tr>
<tr ng-repeat="con in val.details">
<td>{{con.portfolio}}</td>
<td>{{con.status}}</td>
</tr>
<tr ng-repeat-end>
<td colspan="2">Load More</td>
</tr>
</table>
</div>
Code
angular.module("myApp", [])
.controller("myCtrl", ["$scope", function ($scope) {
$scope.data = {"Titles":[{title:"User 1",
details: [{portfolio: "Microsoft", status:"Active"},{portfolio:"IBM", status:"Inactive"}]
}, {title:"User 2",
details: [{portfolio: "Yahoo", status:"Inactive"},{portfolio: "Google", status:"Active"}]
}]};
$scope.LoadData = function(id) {
Change the url as #/Trades/Author/User1
Load the details of the User1
};
});
You could try this. I am using this currently in my project for something very similar. http://joelsaupe.com/programming/angularjs-change-path-without-reloading/
app.run(['$route', '$rootScope', '$location', function ($route, $rootScope, $location) {
var original = $location.path;
$location.path = function (path, reload) {
if (reload === false) {
var lastRoute = $route.current;
var un = $rootScope.$on('$locationChangeSuccess', function () {
$route.current = lastRoute;
un();
});
}
return original.apply($location, [path]);
};
}])
I am trying to get data from the DB and display it using ng-repeat. The getAll function from the factory does the job properly, I get an object with all the data, but it is not displayed properly. In the table I only get the first index, with nothing after it.
If i try with for(i = 0 ; i < DataService.persons.length ; i++), it works fine, but I cannot use it with ng-repeat.
var testReactie = angular.module('testReactie', ['ngRoute']);
testReactie.config(function($routeProvider) {
$routeProvider
.when('/', {
templateUrl : 'instructiuni.ejs'
})
.when('/form', {
templateUrl : 'form.ejs',
controller : 'formContr'
})
.when('/test', {
templateUrl : 'joc.ejs',
controller : 'gameContr'
})
.when('/stat', {
templateUrl : 'scoruri.ejs',
controller : 'statContr',
resolve: {
postPromise:['DataService', function(DataService){
return DataService.getAll();
}]
}
});
});
testReactie.factory('DataService', ['$http', function($http) {
var o = {
persons:[],
person:{}
};
o.getAll = function(){
return $http.get('/db').success(function(data){
o.persons = data;
});
};
o.create = function() {
return $http.post('/db', o.person).success(function(data){
o.persons.push(data);
});
};
return o;
}]);
testReactie.controller('mainContr',function($scope) {
});
testReactie.controller('statContr',function($scope, DataService) {
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
<h2>Scoruri</h2>
<table class="table">
<thead>
<tr>
<th>Nr.</th>
<th>Sex</th>
<th>Varsta</th>
<th>Timp Mediu</th>
</tr>
</thead>
<tbody>
<div ng-repeat = "pers in DataService.persons">
<tr>
<td>{{$index + 1}}</td>
<td>{{pers.sex}}</td>
<td>{{pers.varsta}}</td>
<td>{{pers.timp}}</td>
</tr>
</div>
</tbody>
</table>
</div>
You cannot run a factory as a controller
In your controller do something like
testReactie.controller('mainContr', ['DataService', '$scope', function(DataService, $scope) {
DataService.getAll().then(function(successData){ // a promise helps you do something when it's resolved
$scope.awesomeData = successData;
}
});
Change your factory's get all to be something like
o.getAll = function(){
var promise = $q.defer(); // the $q helps create a promise
return $http.get('/db').success(function(data){
promise.resolve(data); // promise returns data when resolved
});
return promise; // returns a promise
};
your template should be
<div ng-repeat = "pers in awesomeData">
This is because when you have it in your template, it will automatically call $scope.awesomeData. So when you had DataService then it was calling $scope.DataService which was undefined.
I hope this helps.
I fixed the problem. It was from the HTML. I added the ng-repeat directive in a div and it broke the table. After deleting the div and adding the directive in the tag, it worked fine.