Updating angularjs controller with websocket data - angularjs

I'm trying to update my angularjs controller after receiving new information from a websocket server. I am using angular-websockets to create the connection with the websocket server.
Here is my code:
angular.module('VotingApp', ['ngWebSocket'])
.factory('MyVotingResults', function ($websocket) {
// Open a WebSocket connection
var ws = $websocket('ws://localhost:80/test');
//defaults
var collection = {
Question: "This is my question?",
Results: [
{ Percentage: 0, Picture: "http://www.kvmechelen.be/wp-content/uploads/2015/02/De-Witte.jpg", Player: "Seth De Witte", Number: "4", Position: "Defender", Winner: true },
{ Percentage: 0, Picture: "http://www.kvmechelen.be/wp-content/uploads/2016/02/15-16grpsf-037-19715104962_19124904603_o.jpg", Player: "Tim Matthys", Number: "7", Position: "Midfielder", Winner: false },
{ Percentage: 0, Picture: "http://www.kvmechelen.be/wp-content/uploads/2016/02/NICOLAS-VERDIER.jpg", Player: "Nicolas Verdier", Number: "99", Position: "Forward", Winner: false }
]
};
ws.onOpen(function () {
console.log("connectie is open");
ws.send("Hello world!");
});
ws.onClose(function () {
console.log("connectie is closed");
});
ws.onError(function () {
console.log("error!");
});
ws.onMessage(function (response) {
console.log("received an update: ", response);
collection = JSON.parse(response.data);
});
return {
collection: collection,
get: function () {
ws.send(JSON.stringify({ action: 'get' }));
}
};
})
.controller('VotingController', function ($scope, MyVotingResults) {
$scope.Data = MyVotingResults.collection;
})
I am initializing my collection variable with some data to begin. That works and it is shown on the page like it is supposed to.
Here is my html:
<div class="content" ng-controller="VotingController">
<div class="vraag">
<p>{{Data.Question}}</p>
</div>
<div class="antwoorden">
<div class="antw" ng-repeat="result in Data.Results">
<div class="result">
<div class="resultWinner">
<img src="img/winner.png" />
</div>
<div class="resultImage">
<img src="{{result.Picture}}" />
</div>
<div class="resultBalk">
<p><span class="timer">{{result.Percentage}}</span>%</p>
</div>
</div>
<div class="antwText">
<p><span>{{result.Number}}.</span> {{result.Player}}</p>
<p>{{result.Position}}</p>
</div>
</div>
</div>
</div>
My websocketserver is a simple testserver that sends back this json:
{
"Question": "Who deserves the Man of the Match award?",
"Results": [{
"Percentage": 25.0,
"Picture": "http://www.kvmechelen.be/wp-content/uploads/2015/02/De-Witte.jpg",
"Player": "Seth De Witte",
"Number": "4",
"Position": "Defender",
"Winner": false
}, {
"Percentage": 40.0,
"Picture": "http://www.kvmechelen.be/wp-content/uploads/2016/02/15-16grpsf-037-19715104962_19124904603_o.jpg",
"Player": "Tim Matthys",
"Number": "7",
"Position": "Midfielder",
"Winner": true
}, {
"Percentage": 35.0,
"Picture": "http://www.kvmechelen.be/wp-content/uploads/2016/02/NICOLAS-VERDIER.jpg",
"Player": "Nicolas Verdier",
"Number": "99",
"Position": "Forward",
"Winner": false
}]
}
Why won't page update? I based my code on this example:
https://angularclass.github.io/angular-websocket/
Any help is appreciated.
EDIT:
I changed my controller to this but it still doesn't work unfortunately.
.controller('VotingController', function ($scope, MyVotingResults) {
$scope.Data = MyVotingResults.collection;
$scope.$watch(function () {
return MyVotingResults.collection;
}, function (newValue) {
$scope.Data = newValue;
});
})

You can "watch" that service variable in your controller and update the scope accordingly:
$scope.$watch(function () {
return MyVotingResults.collection;
}, function (newValue) {
$scope.Data = newValue;
});

Related

Angularjs drop-down is not showing untill field is changed and loading indicator not work proparely

In my Angularjs app I'm trying to make a drop-down multi select that loads data from JSON at first and when I click on "load more" get more data from JSON and while loading show loading indicator.
But It's not show anything until I change the field and the loading not working proparly.
appreciate any help.
my data is this:
[
{
"item": "South Korea",
"category": "Asia",
"flag": false
}, {
"item": "England",
"category": "Europe",
"flag": false
}, {
"item": "Japan",
"category": "Asia",
"flag": false
}, {
"item": "Denmark",
"category": "Europe",
"flag": false
}, {
"item": "North Korea",
"category": "Asia",
"flag": false
}, {
"item": "Geramany",
"category": "Europe",
"flag": false
}, {
"item": "China",
"category": "Asia",
"flag": false
}, {
"item": "Spain",
"category": "Europe",
"flag": false
}, {
"item": "India",
"category": "Asia",
"flag": false
}, {
"item": "Italy",
"category": "Europe",
"flag": false
}, {
"item": "Tailand",
"category": "Asia",
"flag": false
}, {
"item": "Portugal",
"category": "Europe",
"flag": false
}
]
"use strict";
var app = angular.module("myApp", []);
app.controller("myCtrl", function ($scope, $http) {
/* ===== VARIABLES ===== */
/* loading indicator */
$scope.dataLoading = true;
// data variables
$scope.data2Show = [];
$scope.data = [];
// variables for get requests
var counter = 0;
var chunks = 5;
// variables for checkbox
$scope.selectedItems = [];
//variables for opening dropdown
$scope.selectEnable = false;
// method for opening dropdown
$scope.openSelect = function () {
$scope.selectEnable = !$scope.selectEnable;
};
/* ===== Functions ===== */
// initial success method
function onSuccess(response) {
for (let i = 0; i < chunks; i++) {
$scope.data.push(response.data[i]);
}
counter += chunks;
}
// Error method
function onError(response) {
console.log("error");
}
// load more success method
function loadMoreSuccess(response) {
for (let i = counter; i < (counter + chunks); i++) {
$scope.data.push(response.data[i]);
}
counter += chunks;
}
/* get methods */
// initial get method
$http({
method: "GET",
url: "data.json"
})
.then(onSuccess)
.catch(onError)
.finally(function () {
$scope.dataLoading = false;
});
// load more method
$scope.loadMore = function () {
$http({
method: "GET",
url: "data.json"
})
.then(loadMoreSuccess)
.catch(onError)
.finally(function () {
$scope.dataLoading = false;
});
};
/* when checkbox changes if the item is checked
is alteady in the selected
items it will remove it because it means that
the checkbox is unchecked and if the item
is not in selected items it will add that */
$scope.itemChecked = function (data) {
var selected = $scope.selectedItems.indexOf(data.item);
if (selected == -1) {
$scope.selectedItems.push(data.item);
} else {
$scope.selectedItems.splice(selected, 1);
}
};
// when the searchField content changes this function executes
$scope.filter = function () {
if (!$scope.searchField) {
$scope.data2Show = angular.copy($scope.data);
/* if searchField is empty make a copy of our data */
} else {
/* if searchField is not empty data2show will be empty and iterate the data array and for each element if the searched sentence is in the data array that data will be pushed into the data2show array */
$scope.data2Show = [];
$scope.data.map(function (itm) {
if (itm.item.indexOf($scope.searchField) != -1) {
$scope.data2Show.push(itm);
}
});
}
};
});
ul li {
list-style: none;
text-align: center;
}
ul {
height: 100px;
overflow-y: scroll;
}
#loadMore {
text-align: center;
color: #aaa;
background: #ddd;
cursor: pointer;
}
#category {
text-align: center;
background: #ddd;
}
#listContainer {
width: 20%;
}
span {
cursor: pointer;
}
<!DOCTYPE html>
<html lang="en" ng-app="myApp">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.0/angular.js
"></script>
<link rel="stylesheet" href="stylesheet/style.css">
</head>
<body ng-controller="myCtrl">
<input type="text" ng-click="openSelect()">
<div id="selectContainer" ng-show="selectEnable">
<div>{{selectedItems.toString()}}</div>
<input type="text" id="searchField" ng-model="searchField" ng-change="filter()">
<div id="listContainer">
<ul id="innerContainer">
<li ng-repeat="data in data2Show" ng-model="data2show">
<input type="checkbox" ng-change="itemChecked(data)" name="select" ng-model="data.flag" ng-checked="isChecked(data)"> {{data.item}}
</li>
<div ng-show="dataLoading" ng-model="dataLoading">loading...</div>
<li id="loadMore" ng-click="loadMore()">
load more
</li>
</ul>
</div>
</div>
<script src="script/script.js"></script>
</body>
</html>
Loading indicator: For the loading indicator to show $scope.dataLoading has to be set to true. This is only done once initially. It should also be done in the $scope.loadMore method before the call to HttpService.get
New Elements not shown: You store the elements that you load in the $scope.loadMore only in $state.data. To be displayed they must also be stored in $scope.data2show. So just invoke $scope.filter after the new elements have been loaded from the server.

Asynchronous Angular-bootsrap-UI typeahead: select directive issue

My application is using the Angular-Bootstrap-UI-Typeahead feature for auto complete.
As the user types, i'd like to be able to call an API & return similar strings.
I've followed the guidance here, and everything works fine with the out of box Google API.
I've also successfully swapped in my own API: I am able to call the API, get the data, and log it in the correct format in my browser console.
However, I constantly get "no results found" from the text box. I suspect this may be a problem with the select directive, but i am stumped.
I would greatly appreciate any guidance on this!
Here is some code:
UI (content.html)
<h4>biz results</h4>
<pre>Model: {{user.orgName | json}}</pre>
<input type="text"
ng-model="user.orgName"
placeholder="Locations loaded via $http"
uib-typeahead="obj for obj in getLocation($viewValue)"
typeahead-loading="loadingBiz"
typeahead-no-results="noBiz" class="form-control"
typeahead-wait-ms="700">
<i ng-show="loadingBiz" class="glyphicon glyphicon-refresh"></i>
<div ng-show="noBiz">
<i class="glyphicon glyphicon-remove"></i> No Results Found
</div>
Angular (script.js)
$scope.getLocation = function(val) {
var bizRequest = $http.post('/sample', {
// var bizRequest = $http.post('/biz', {
orgName: val,
limit: 5
}
).success(function(response){
console.log(response)
//console.log('Biz response: ' + JSON.stringify(response))
//console.log(response.data.fields.map(item))
var bizArray = response.data.fields.map(function(item){
return item.fields.orgName;
});
console.log(bizArray);
return bizArray;
});
console.log("Biz Request /////// " + JSON.stringify(bizRequest))
return bizRequest
};
Node API (app.js)
app.post('/sample', function(req, res){
var resp = {
"success": true,
"data": {
"fields": [{
"fields": {
"scid": "1111",
"orgName": "1111",
"countryCode": "1",
"countryName": "1",
"cityName": "1",
"addressLine": "1111"
},
"matchedRule": {
"duplicateLevel": "POTENTIAL_MATCH",
"id": "18",
"rank": "1"
}
}, {
"fields": {
"scid": "2222",
"orgName": "2222",
"countryCode": "22",
"countryName": "22",
"cityName": "22",
"addressLine": "2 22"
},
"matchedRule": {
"duplicateLevel": "POTENTIAL_MATCH",
"id": "18",
"rank": "1"
}
}]
},
"errors": [],
"warnings": [],
"infoMessages": []
}
res.send(JSON.stringify(resp))
})
You have to return promise from getLocation method while dealing asynchronous typeahead. So don't use .success there which would break promise chain. Instead use .then which would help you to chain promise and you can return data from .then to pass it to typeahead
$scope.getLocation = function(val) {
var bizRequest = $http.post('/sample', {
// var bizRequest = $http.post('/biz', {
orgName: val,
limit: 5
}
).then(function(data){
response = data.data; //<-- take data in response.
console.log(response.data)
//console.log('Biz response: ' + JSON.stringify(response))
//console.log(response.data.fields.map(item))
var bizArray = response.data.fields.map(function(item){
return item.fields.orgName;
});
console.log(bizArray);
return bizArray;
});
console.log("Biz Request /////// " + JSON.stringify(bizRequest))
return bizRequest
};

angular.forEach() not working

Hi friend I'm beginner in angular and getting stuck by using angular.forEach() function. I just want to call data from a nested array in data.json file. Please check my code below... ****I want to call data from --users-- key****
HTML
<div class="user-container" ng-controller="users">
<ul class="list">
<li ng-repeat="(key, value) in items">
{{key}} <p> {{value}}
</li>
</ul>
</div>
Problems with current code
When run my code in browser Its giving me only 2 <li> in ng-repeat then in {{Key}} I'm getting 0 in first <li> and 1 in second <li>
and in {{value}} I'm getting whole user list in first <li> and in second <li> their is no data
data.json
{
"data": {
"new": true,
"show_page": false,
"status": "signedin",
"users": [{
"Michele": {
"logo": "xyz.jpg",
"status": "active",
"active_since": 2015,
"order": 1
},
"Gerry": {
"logo": "xyz.jpg",
"status": "active",
"active_since": 2015,
"order": 1
}
}]
},
"success": true
}
Controller.js
var myApp = angular.module('app', []);
myApp.service('userData', ['$http', function($http){
return{
userslist : function(){
return $http({'url' : 'data.json', 'method' : 'GET'}).then(function(response){
return response.data;
}, function(data){
console.log(data)
})
}
}
}]);
myApp.controller('users', ['$scope', '$http', 'userData', function($scope, $http, userData){
userData.userslist().then(function(data){
//var provideDataKey = Object.keys(data.users)[0];
$scope.items = [];
angular.forEach(data, function(item){
//console.log(item.users);
$scope.items.push(item.users)
})
console.log($scope.items)
})
}]);
response is the HTTP response, with its body (data), headers, etc.
So response.data is the body, which looks like this:
{
"data": {
"new": true,
"show_page": false,
"status": "signedin",
"users": [{
"Michele": {
"logo": "xyz.jpg",
"status": "active",
"active_since": 2015,
"order": 1
},
"Gerry": {
"logo": "xyz.jpg",
"status": "active",
"active_since": 2015,
"order": 1
}
}]
},
"success": true
}
What you want is to access the users field of the data field of this body. So what you want is
userData.userslist().then(function(data){
$scope.items = data.data.users;
console.log($scope.items)
})
$scope. items is an array, not an object. You want to display the elements of this array. So the syntax is:
{{ user }}
Your JSON is awful, because each user is an object with a single field, and you have no way of knowing the name of that field. You'd better change it to
"users": [
{
"name": "Michele",
"logo": "xyz.jpg",
"status": "active",
"active_since": 2015,
"order": 1
},
{
"name": "Gerry",
"logo": "xyz.jpg",
"status": "active",
"active_since": 2015,
"order": 1
}
]
That way you could just do:
<li ng-repeat="user in items">
{{ user.name }}, active since {{ user.active_since }}.
use this
myApp.controller('users', ['$scope', '$http', 'userData', function($scope, $http, userData){
userData.userslist().then(function(data){
//var provideDataKey = Object.keys(data.users)[0];
$scope.items = [];
angular.forEach(data.users[0], function(item){
$scope.items.push(item);
})
console.log($scope.items)
})
}]);
you were iterating over data and not on users.

How to display my JSON datas expressjs/angularjs

I am a beginner in JSON.
I would like to display all my JSON datas in my html <div>, but I am not sure how to do it with an object using EXPRESSJS.
Find bellow my JSON Datas
app.post("/form",function(req,res)
{
var departure=req.body.departure;
var destination=req.body.destination;
response = {
"flights": [{
"departure": departure,
"destination": destination,
"time": {
departure: 10,
destination: 12
},
"price": 2000
}, {
"departure": departure,
"destination": destination,
"time": {
departure: 12,
destination: 14
},
"price": 4000
}, {
"departure": departure,
"destination": destination,
"time": {
departure: 14,
destination: 16
},
"price": 8000
}]
};
res.json({departure: departure, destination: destination});
});
My html
<div ng-repeat="item in response">
<dir>{{item.departure}}</dir>
<dir>{{item.destination}}</dir>
<dir>{{item.time.departure}}</dir>
<dir>{{item.time.destination}}</dir>
<dir>{{item.price}}</dir>
</div>
AngularJS code
app.controller('formController', function($scope, $http) {
$scope.pageClass = 'form';
$scope.departure = '';
$scope.destination = '';
$scope.submit = function() {
$http.post('/form', {
departure: $scope.departure,
destination: $scope.destination
}).then(function(res) {
$scope.response = res.data;
});
}
});
At the moment it is displaying only my departure and destination as I asked. Is there a way to display all my datas by writing my res.json() without doing it variable by variable ? I guess I have to do something with ng-repeat as well ?
Thank you by advance
Yes, you need use ng-repeat
var app = angular.module('app',[]);
app.controller('myController',function($scope){
$scope.response = {
"flights": [{
"departure": "departure1",
"destination": "destination1",
"time": {
departure: 10,
destination: 12
},
"price": 2000
}, {
"departure": "departure2",
"destination": "destination2",
"time": {
departure: 12,
destination: 14
},
"price": 4000
}, {
"departure": "departure3",
"destination": "destination3",
"time": {
departure: 14,
destination: 16
},
"price": 8000
}]
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app">
<div ng-controller="myController">
<div ng-repeat="item in response.flights">
<dir>{{item.departure}}</dir>
<dir>{{item.destination}}</dir>
<dir>{{iteme.time.departure}}</dir>
<dir>{{item.time.destination}}</dir>
<dir>{{item.price}}</dir>
</div>
</div>
</div>
check the docu: https://docs.angularjs.org/api/ng/directive/ngRepeat
you do need to use a ng-repeat
<div ng-repeat="flight in response.flights">
<dir>{{flight.departure}}</dir>
<dir>{{flight.destination}}</dir>
<dir>{{flight.time.departure}}</dir>
<dir>{{flight.time.destination}}</dir>
<dir>{{flight.price}}</dir>
</div>
Reference for ngRepeat
A good reference for anything Angular can be found on the documentation site for AngularJS

Stuck: AngularJs using factory with http call to json

I am struck and not able to understand the issue here.
I created a factory using http service call to my json file
Factory (accountInfo.json):
appRoot.factory('accountInfo', ['$http', function($http) {
return $http.get('../../accountInfo.json')
.success(function(data) {
return data;
})
.error(function(err) {
return err;
});
}]);
controller(AccountsController.js)
appRoot.controller('AccountsController', ['$scope', 'accountInfo', function($scope, accountInfo){
accountInfo.success(function(data) {
$scope.rows = data;
});
$scope.totals = {
name: '',
marketValue: 0,
cash: 0,
legend: 'none'
};
for (var i = 0; i < $scope.rows.length; i++) {
$scope.totals.marketValue += $scope.rows[i].marketValue;
$scope.totals.cash += $scope.rows[i].cash;
}
$scope.addAccount = function() {
$scope.rows.push({
name: 'New Account',
marketValue: Math.random() * 100000,
cash: Math.random() * 400000,
legend: 'cyan'
});
}
}]);
My json (accountInfo.json)
[{
"name": "Brokerage Account 3",
"marketValue": 1999990,
"cash": 1995826,
"legend": "orange"
},
{
"name": "Account 3",
"marketValue": 1949990,
"cash": 1695856,
"legend": "darkorange"
},
{
"name": "Brokerage Account 1",
"marketValue": 1349990,
"cash": 1595866,
"legend": "red"
},
{
"name": "Brokerage Account 4",
"marketValue": 155990,
"cash": 160826,
"legend": "blue"
},
{
"name": "Brokerage Account 2",
"marketValue": 74560,
"cash": 19956,
"legend": "gray"
},
{
"name": "Account 4",
"marketValue": 55006,
"cash": 53006,
"legend": "salmon"
},
{
"name": "Account 13",
"marketValue": 37340,
"cash": 0,
"legend": "green"
},
{
"name": "Joint Account 1",
"marketValue": 28308,
"cash": 4167,
"legend": "darkblue"
},
{
"name": "Joint Account 2",
"marketValue": 10000,
"cash": 10000,
"legend": "teal"
}]
Error I am receiving is "$scope.rows is undefined"
Controller is not able to access $scope.rows outside success function.
Thanks :)
You need to resolve the promise in your controller, not in your factory, just return the promise:
appRoot.factory('account', ['$http', function($http) {
return {
info: function () {
return $http.get('../../accountInfo.json');
}
}
}]);
Then in your controller do:
appRoot.controller('AccountsController', ['$scope', 'account', function($scope, account){
account.info()
.success(function(data) {
$scope.rows = data;
})
.error(function(err) {
return err;
});
}]);
FYI, the success and error methods are deprecated:
The $http legacy promise methods success and error have been deprecated. Use the standard then method instead. If $httpProvider.useLegacyPromiseExtensions is set to false then these methods will throw $http/legacy error.
See: https://docs.angularjs.org/api/ng/service/$http
Use the then method:
account.info().then(
function resolved (response) {
$scope.rows = response.data;
},
function rejected (response) {
alert(response.status + ': ' + response.statusText);
}
);
Here's a working example of the concept: http://plnkr.co/edit/UtJDpvBKKYl4rBzgXYo4?p=preview
You should return a function which fetches the data when you call it like so:
appRoot.factory('accountInfo', ['$http', function($http) {
return {
fetchData: fetchData
};
function fetchData() {
return $http.get('../../accountInfo.json');
}
}]);
then in your controller you can do:
accountInfo.fetchData()
.then(
function(data) {
console.log(data);
},
function(error) {
console.log(error);
}
);
Thank you all for the help.
I solved my issues by bootstraping the app. I was not able to access my data initially since the http call was not completed.
angular.element(document).ready(function() {
angular.bootstrap(angular.element(document), ['app']);
});

Resources