I am trying to fill a table via AngularJS.
My controller receives through a socket data.
The data looks like:
[{score: 2, team: 1, kills: 9, assists: 2, deaths: 0}, {score: 2, team: 1, kills: 9, assists: 2, deaths: 0}]
I tried to reduce the code to the relevant stuff, but maybe I did something wrong by that, but the jade templates renderes usually.
index.jade
doctype html
html(lang='en', ng-app="app")
head
meta(charset='utf-8')
meta(http-equiv='X-UA-Compatible', content='IE=edge')
meta(name='viewport', content='width=device-width, initial-scale=1')
title= title
// Bootstrap CSS
link(href='stylesheets/bootstrap.min.css', rel='stylesheet')
// Socket
script(src='https://cdn.socket.io/socket.io-1.3.5.js')
// jQuery
script(src='http://code.jquery.com/jquery-2.1.3.min.js')
// Angular
script(src='https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js')
script(src='javascripts/controller.js')
// Main CSS
link(href='stylesheets/main.css', rel='stylesheet')
body(ng-controller="controller")
.content.row
.col-md-12.data
.table-responsive
table.table.table-hover
thead
tr
th Score
th Kills
th Assists
th Deaths
tbody
tr(ng-repeat="1 in data")
td {{1.score}}
td {{1.kills}}
td {{1.assists}}
td {{1.deaths}}
script(src='javascripts/bootstrap.min.js')
controller.js
var app = angular.module('app', []);
app.controller('controller', function($scope) {
var socket = io('http://localhost:8080');
socket.on('data', function(data) {
$scope.data = data;
});
});
My controller receives the data and when I do console.log($scope.data) it returns me my sent data.
The problems must be somewhere in the jade template.
You need to do $scope.$apply() after assigning data in socket.on('data' event. Because udpating scope variable through an events will not run digest cycle. you need to run it manually by call $apply() on $scope or either you could wrap function inside $scope.$apply(function(){ //do scope variable updation from here })
Code
var app = angular.module('app', []);
app.controller('controller', function($scope) {
var socket = io('http://localhost:8080');
socket.on('data', function(data) {
$scope.data = data;
$scope.$apply();
});
});
Related
When I combine AngularJS (1.6.x) with jQuery data-tables, I get alert error:
Cannot reinitialise DataTable
First I use AngularJS to bind and fill data-tables,
then I try to add Individual column searching (text inputs) feature.
Individual column searching (select inputs)
AngularJS initialize data-tables, but does not give me a handle.
Here is my code:
var app1=angular.module('formvalid', ['ui.bootstrap','ui.utils']);
app1.controller('validationCtrl',function($scope){
angular.element(document).ready(function () {
// Setup - add a text input to each footer cell
$('#example tfoot th').each( function () {
var title = $(this).text();
$(this).html( '<input type="text" placeholder="Search '+title+'" />' );
} );
console.log(' document ready function, add search by column feature ');
var table = $('#example').DataTable();
// Apply the search
table.columns().every( function () {
var that = this;
$( 'input', this.footer() ).on( 'keyup change', function () {
if ( that.search() !== this.value ) {
that
.search( this.value )
.draw();
}
} );
} );
});// document ready
$scope.data=[[
"Tiger Nixon",
"System Architect",
"Edinburgh",
"5421",
"2011\/04\/25",
"$320,800"
]];
$scope.dataTableOpt = {
//custom datatable options
// or load data through ajax call also
// "data": $scope.data00, // this is not real binding, the real binding is ui-jq="dataTable" ui-options="dataTableOpt", fill $scope.data
"aLengthMenu": [[10, 50, 100,-1], [10, 50, 100,'All']],
};
});
demo on codepen.io
demo on jsFiddle
earlier angularjs initialize datatable( must add "retrieve": true, otherwise, will get above error retrieve existing table handle) , but don't get a table handle,
later here, $('#id').DataTable(); will 1) if existing, will retrieve table handle.
2) if not exsiting, will create a new table.
so the solution is
$scope.dataTableOpt = {
//custom datatable options
// or load data through ajax call also
// "data": $scope.data00, // this is not real binding, the real binding is ui-jq="dataTable" ui-options="dataTableOpt", fill $scope.data
"retrieve": true, // angularjs at begining initialize datatable, but don't get a handle to the table, later you want to add search column, you need to get the table handle.
"aLengthMenu": [[10, 50, 100,-1], [10, 50, 100,'All']],
};
codepen : ui-grid (angularjs 1.x) demo
jsFiddle : ui-grid (angularjs 1.x) demo
var app = angular.module('app', ['ngAnimate', 'ngTouch', 'ui.grid', 'ui.grid.exporter', 'ui.grid.selection']);
app.controller('MainCtrl', ['$scope', '$http', '$interval', '$q','uiGridConstants', function ($scope, $http, $interval, $q, uiGridConstants) {
I build those demo, is best solution for angularjs 1.x datatable.
angularjs 1.x + jquery(datatables) isn't best solution.
ui-grid is pure angularjs 1.x, is best solution so far.
I am still learning angular and in my example projekt I have a problem on updating the view.
Got this in my header ....
<meta charset="UTF-8">
<title>{{ name }}</title>
And this in my body:
<body ng-controller="BodyController as body">
<input type="button" ng-click="changeTitle()" name="changeNameButton" value="change name"/>
This is my head controller:
myApp.controller('HeadController',
['$scope', 'ApplicationService', 'DataService', 'UserService', function ($scope, ApplicationService, DataService, UserService) {
var self = this;
$scope.name = ApplicationService.getTitle();
}]
);
And here is my body controller:
myApp.controller('BodyController', ['$scope', 'ApplicationService', function ($scope, ApplicationService) {
$scope.text = 'Hello, Angular fanatic.';
$scope.changeTitle = function () {
console.log('change the title');
ApplicationService.setTitle('test');
}
}]);
This is my application service
myApp.service('ApplicationService', ['ConfigurationService', function(ConfigurationService){
this.title = '';
this.setTitle = function (newTitle) {
console.log('new title (setter): ' + this.title);
this.title = newTitle
}
this.getTitle = function () {
if(this.title==''){
this.title = ConfigurationService.title + ' | ' + ConfigurationService.subtitle;
}
console.log('new title (getter): ' + this.title);
return this.title;
}
}]);
So far so good and sorry that I do not use codepen, etc. But it was not working in it, ...
My Problem: It is setting the title on initial load of the website, but not on pressing the button. The new name is set to ApplicationService.title, but header controller does not update it. Whats is wrong in this case? How can I update the title in the view...?
Regards
n00n
see the codepen for it: https://codepen.io/n00n/pen/bqaGKY
What you're doing is the equivalent of the following simple code:
//in the header controller
var name = service.getTitle();
// in the header template
display(name);
// later, in the body
service.setTitle('test');
// in the header template
display(name);
You see that this can't work: the variable name in the header controller has been initialized when the controller was created, and assigning a new value to the title stored in the service can't magically change the value of the name variable in the header controller. What you want is to display the title in the service:
<title>{{ getTitle() }}</title>
$scope.getTitle = function() {
return ApplicationService.getTitle();
};
That didn't work because you're calling getTitle method when title wasn't set. So that's it is referring to older title('undefined'). You can change your binding to
$scope.getTitle = ApplicationService.getTitle;
And then change HTML to
{{getTitle()}}
So title will get fetch from service and updated on the page on each digest cycle.
Other thing which I'd like to mention is, don't use(mix) $scope when you are using controllerAs, so then remove $scope from controller and bind data to below
var vm = this;
vm.getTitle = ApplicationService.getTitle;
Is there any way that I can create a template in AngularJS but not run it until some event?
Actually I am using SignalR. So when server calls a client function then I want some HTML to show based on the data sent by server.
Suppose I am making a Chess Game.
I donĀ“t have the board to display on the page until the server sends it.
In HandleBar I can create a template and when the server sends the board in json format I can compile the template and display it on page.
gameHub.client.buildBoard = function(game){
var template = Handlebars.compile($("board-template").html());
$("board").html(template(game.Board))
}
This builBoard function gets called by server.
In AngularJS I have to create a Controller, but the $scope.board has not loaded let.
The angular Code is
<div ng-app="game">
<div ng-controller="boardController">
<div ng-repeat="row in board.Pieces">
// Display Pieces
</div>
</div>
JS
var app = angular.module("game", []);
app.controller("boardController", function ($scope) {
$scope.size = 5;
$scope.board= [];
});
Here the board is initialized to empty array.
Now the server will call the buildBoard() function with the necessary data required.
gameHub.client.buildBoard = function(board){
// Code to take this board object and assign it to the $scope.board
}
From here (outside the scope of controller ), how can I update the $scope.board array?
While I believe you should explain yourself a bit more, and show some angular code, I think you are looking for a solution to a problem that angular doesn't have.
Consider this code:
<div class="board-thing" ng-bind-html="board" ng-hide="board === null"></div>
...
.controller('myController', function($scope) {
$scope.board = null;
gameHub.client.buildBoard = function(game) {
$scope.board = game.board;
});
})
When the data is loaded $scope.board is assigned to the data and the view is immediately updated through the scope and ng-bind-html. No need for any compilation!
You can define directives to avoid cluttering your controller with presentation related code.
For all business related code, define services outside of your controller.
In this case, as you want push data, you need to define an event dispatcher ("Server") that will inform the controller when remote changes take place.
Here is an example controller and related template.
angular
.module('app')
.controller("ChessController", function($scope, Server) {
$scope.list = [0, 1, 2, 3, 4, 5, 6, 7];
$scope.pieces = [];
// "Server" is an angular service that abstracts your connection with your server
// which can be based on socket.io, a raw websocket, HTTP polling...
var chessGame = Server.getChessGame('xxx');
chessGame.on('init', function(pieces) {
// pieces == [
// {x: 0, y: 0, type: "pawn", color: "white"}
// {x: 0, y: 3, type: "king", color: "white"}
// {x: 2, y: 0, type: "queen", color: "white"}
// ];
$scope.pieces = pieces;
});
chessGame.on('remote_piece_moved', function(move) {
// remove pieces at destination
$scope.pieces = $scope.pieces.filter(function(p) { return p.x != move.dest_x && return p.y != move.dest_y; })
// move piece.
var piece = $scope.pieces.find(function(p) { return p.x == move.start_x && p.y == move.start_y; });
piece.x = move.dest_x;
piece.y = move.dest_y;
});
});
.directive('chessPiece', function() {
return {
scope: false,
link: function(scope, element) {
scope.$watch('pieces', function(pieces) {
var piece = pieces.find(function(p) { return p.x == scope.col && p.y == scope.row; });
if (piece)
element.html('<img src="pieces/' + piece.type + '-' + piece.color + '.jpg"/>')
else
element.html('');
}, true);
}
}
});
Template
<table ng-controller="ChessController">
<tr ng-repeat="row in list">
<td ng-repeat="col in list" chess-piece></td>
</tr>
</table>
I have a directive, <flightpoint></flightpoint>.
I need to add this directive to Mapquest's map via map.addShape().
However, angular is not aware of the new directive on the map, therefore it doesn't process it (its blank html).
MQA.withModule('htmlpoi', function() {
var poi=new MQA.HtmlPoi( {lat:39.743943, lng:-105.020089} );
poi.setHtml("<flightpoint></flightpoint>", -6, -20, 'mqa_nostyle_htmlpoi');
var x = routeMap.addShape(poi);
});
A few things I've tried.....
1. $compile
MQA.withModule('htmlpoi', function() {
var poi=new MQA.HtmlPoi( {lat:39.743943, lng:-105.020089} );
poi.setHtml($compile("<flightpoint></flightpoint>")($scope), -6, -20, 'mqa_nostyle_htmlpoi');
var x = routeMap.addShape(poi);
$scope.$apply();
});
Result: [object Object] is displayed on the map instead of my directive.
2. angular.bootstrap()
MQA.withModule('htmlpoi', function() {
var poi=new MQA.HtmlPoi( {lat:39.743943, lng:-105.020089} );
poi.setHtml("<flightpoint></flightpoint>", -6, -20, 'mqa_nostyle_htmlpoi');
var x = routeMap.addShape(poi);
angular.bootstrap(document, ['app']);
});
Result: "Error: App Already Bootstrapped with this Element 'document'"
If I was able to compile it after its been added that would be okay too.
This is a little sloppy but its working for me.
I'm able to add a dummy tag and insert compiled angular into it.
MQA.withModule('htmlpoi', function() {
var poi=new MQA.HtmlPoi( {lat:39.743943, lng:-105.020089} );
poi.setHtml("<span id=\"insertDirectiveHere\"></span>", -6, -20, 'mqa_nostyle_htmlpoi');
routeMap.addShape(poi);
// now that you've added the span we can insert compiled angular on that tag
var domElem = document.getElementById('insertDirectiveHere');
domElem.innerHTML = "<flightpoint></flightpoint>";
$compile(domElem)($scope);
});
I am creating a pop-up modal that I want to have the capabilities of being updated dynamically using a newly created $scope. I want to do something like this:
var myNewScope = $scope.$new();
myNewScope.name = 'Jack';
ModalService.open('Hello, {{ name }}', myNewScope);
Then in my ModalService.open method I want to compile that string with the given scope like this
// ... other service stuff
service.open = function(template, scope){
var compiledText = $compile(template)(scope);
// I want compiledText = 'Hello, Jack'
}
Welp... I don't think angular has a built in way to do this.. so I just built my own version.
app.controller('TestController', function($scope, $compile){
var scope = $scope.$new();
scope.percentage = {Value:55};
scope.name = 'Jack';
var msg = 'We are at {{ percentage.Value }}% done, {{ name }}.. {{ 4/3 }}';
var element = msg.replace(/{{\s*([a-zA-Z0-9+-/*//\s.]*)\s*}}/g, function($0, $1){
return scope.$eval($1);
} );
console.log(element); // prints 'We are at 55% done, Jack.. 1.3333333333333333'
});
This seems to be working pretty well