I would like to use Angular as a template engine then I want to give the generated HTML code to another library.
I have a template file template.html:
<div><h1><span data-ng-show="details.rs">{{details.rs}}</span></h1></div>
I would like to use Angular to generate the final HTML according to what I have in my scope.
For example if details.rs=="Hi!" :
<div><h1><span>Hi !</span></h1></div>
I tried to use the $compile tool but I only get the original HTML. Here is a small sample :
var getTemplate = function (templateName) {
var defer = $q.defer();
if ($templateCache.get(templateName)) {
defer.resolve($templateCache.get(templateName));
} else {
$http.get(templateName, {cache: $templateCache}).then(function (data) {
defer.resolve(data);
});
}
return defer.promise;
};
var prepareTemplate = function (templateName) {
var defer = $q.defer();
getTemplate(templateName).then(function (htmlTemplate) {
defer.resolve($compile(htmlTemplate));
});
return defer.promise;
};
var buildMarkerPopup = function (properties) {
var defer = $q.defer();
prepareTemplate('views/template.html').then(function (template) {
var scope = $scope.$new();
scope.details = properties;
$timeout(function () {
var htmlElement = template(scope);
$log.debug(htmlElement);
defer.resolve(htmlElement);
});
});
return defer.promise;
};
Does anyone know what I missed ?
Best regards
I think you need $interpolate for that
http://jsfiddle.net/HB7LU/9977/
var exp = $interpolate('<div><h1><span data-ng-show="details.rs">{{details.rs}}</span></h1></div>');
var context = {
details: {
rs: 'Hi!'
}
};
var result = exp(context);
console.log(result)
Related
I have the following global helper:
Template.registerHelper('results',function(){
var valuationId = this._id;
var valuation = Valuations.findOne({_id: valuationId});
var targetId = this.targetId;
var targetTicker = Companies.findOne({_id:targetId}).ticker;
var targetData = CompaniesData.findOne({ticker: targetTicker});
return {
peFy1: targetData.epsFy1 * valuation.PriceEarningsFy1,
peFy2: targetData.epsFy2 * valuation.priceEarningsFy2
}
});
When I call this helper through HTML, like so, it works fine:
<div>
{{results.peFy1}}
</div>
I am not able to display the value when calling the helper through Javascript, per this answer.
<div>
{{peFy1}}
</div>
Template.ValuationResults.helpers({
peFy1: function() {
return UI._globalHelpers.results().peFy1;
}
});
I've tried writing this in a couple other ways but none work:
return UI._globalHelpers['results']().peFy1;
return Template._globalHelpers.results().peFy1;
For what it's worth, UI._globalHelpers gives an error in Webstorm as being unresolved variables.
I thought the problem might be that I am not passing any parameters to the function, but it works fine through HTML so shouldn't be necessary. Also, adding console.log(this._id) and console.log(this.targetId) within the test helper both return correct results, so those are valid.
CORRECT CODE USING ANSWER BELOW:
getResults = function(valuationId,targetId){
var valuation = Valuations.findOne({_id: valuationId});
var targetTicker = Companies.findOne({_id:targetId}).ticker;
var targetData = CompaniesData.findOne({ticker: targetTicker});
return {
peFy1: targetData.epsFy1 * valuation.priceEarningsFy1,
peFy2: targetData.epsFy2 * valuation.priceEarningsFy2
}
};
Template.registerHelper('results',function(){
return getResults();
});
Template.Valuation.helpers({
peFy1: function() {
var valuationId = this._id;
var targetId = this.targetId;
return getResults(valuationId,targetId).peFy1;
},
peFy1: function() {
var valuationId = this._id;
var targetId = this.targetId;
return getResults(valuationId,targetId).peFy1;
}
});
Your use of UI._globalHelpers.results().peFy1 looks correct syntactically.
However as an alternative option that sidesteps the Meteor (UI._globalHelpers) api, create a standard JavaScript function like this:
getResults = function(){
var valuationId = this._id;
var valuation = Valuations.findOne({_id: valuationId});
var targetId = this.targetId;
var targetTicker = Companies.findOne({_id:targetId}).ticker;
console.log('targetId: ' + targetId);
console.log(Companies.findOne({_id:targetId})),
var targetData = CompaniesData.findOne({ticker: targetTicker});
return {
peFy1: targetData.epsFy1 * valuation.PriceEarningsFy1,
peFy2: targetData.epsFy2 * valuation.priceEarningsFy2
}
};
Template.registerHelper('results',function(){
return getResults();
});
Use results helper in templates and getResults function in JavaScript.
I am using angularJS. Right now I have a function that creates a "new project" (an object) which sends it to the server.
The sidebar is populated with a list of projects that it gets from the server. Each time the page is reloaded is calls a function "loadProjects" and it generates the list.
To make a new project appear on the sidebar without having to refresh the page I made a timeout function because if I call both the "postProject" and "loadProjects" it would not work.
function RefreshSidebar() {
setTimeout(loadProjects, 200);
}
This code works but I want to make it doesn't feel right. I want to make it right and I think I should be using a promise call for this. The problem that I am facing is that the first function being called (addProject) is inside a Controller for the "Add new Project" custom directive and the second one is inside the mainController.
This is my app.directive.js:
(function() {
angular
.module("app.directive", [])
.directive("createProject", CreateProjDirective)
.directive("viewProject", ViewProjDirective);
function ViewProjDirective() {
return {
restrict: "EA",
templateUrl: "directives/project_view.html"
};
}
function CreateProjDirective() {
return {
restrict: "EA",
controller: CreateController,
controllerAs: "proj",
templateUrl: "directives/create_project.html"
};
}
function CreateController($scope, $http, $timeout) {
var proj = this;
var counter = 001;
proj.id = "ProjectTest_"+counter
proj.uuid = "";
proj.customer = "";
proj.socket = "";
proj.drawing = "";
proj.programmer = "";
proj.createdOn = new Date();
proj.revision = "";
proj.protocol = "";
proj.targetMachineId = "";
$scope.posttest = "";
proj.addProject = function(){
var dataProj = {
"Description": {
ProjectID: proj.id,
UUID: proj.uuid,
Customer: proj.customer,
Socket: proj.socket,
Drawing: proj.drawing,
Programmer: proj.programmer,
CreatedOn: proj.createdOn,
Revision: proj.revision,
ProtocolFileSchema: proj.protocol,
TargetMachineID: proj.targetMachineId
}
};
var request = $http.post('http://localhost:9001/api/projects/', dataProj) ;
request.success(function(data, status, headers, config) {
console.log(data);
$scope.message = data;
});
request.error(function(data, status, headers, config) {
alert( "failure message: " + JSON.stringify({data: data}));
});
//reset the form
counter = counter + 1;
proj.id = "ProjectTest_"+counter;
proj.uuid = "";
proj.customer = "";
proj.socket = "";
proj.drawing = "";
proj.programmer = "";
proj.createdOn = new Date();
proj.revision = "";
proj.protocol = "";
proj.targetMachineId = "";
$scope.posttest = "";
}
};
})();
And this is my app.controller.js (I think the only relevant functions here is loadProjects() and refreshSidebar()
(function() {
angular
.module("app.controller", [])
.controller('AppCtrl', MainController);
MainController.$inject = ['$scope', '$mdSidenav', 'ilcamService', '$timeout','$log', "$http"];
function MainController($scope, $mdSidenav, ilcamService, $timeout, $log, $http) {
var allProjects = [];
//com directive-controller $scope.$on("testEvent", function(event, data) { $scope.test = data; console.log(data); });
$scope.create = false;
$scope.selected = null;
$scope.projects = allProjects;
$scope.selectProject = selectProject;
$scope.toggleSidenav = toggleSidenav;
$scope.refreshSidebar = refreshSidebar;
$scope.putProject = putProject;
loadProjects();
function loadProjects() {
ilcamService.loadAll()
.then(function(projects){
allProjects = projects;
console.log(projects);
$scope.projects = [].concat(projects);
$scope.selected = $scope.projects[0];
})
}
function toggleSidenav(name) {
$mdSidenav(name).toggle();
}
function selectProject(project) {
$scope.selected = angular.isNumber(project) ? $scope.projects[project] : project;
$scope.toggleSidenav('left');
$scope.create = 0;
}
function refreshSidebar() {
setTimeout(loadProjects, 200);
}
})();
My first idea was to inject the "app.directive" inside the "app.controller" so I could use addProject inside the controller, just like I injected "IlcamService" to use the "loadAll" but angular don't seem to allow me to inject a directive inside a controller. That makes sense because I actually want the controller that is inside that directive, not the entire directive but I dont know how to do that without moving the controller outside the directive file.
Create a service that will be responsible to make the requests, this service will have a method that returns a promise. Inside your controller inject the service and call the method that make the requests, when the promise resolves call then loadProjects method. Something like:
Service
app.service('LoadProjectsService', function($http){
_postProjects = function(){
return $http.post(...)
}
return{
postProjects: _postProjects
}
});
Controller
app.controller('YourController', ['LoadProjectsService', function(LoadProjectsService) {
LoadProjectsService.postProjects()
.success(
loadProjects()
)
}]);
Directive
app.directive('LoadProjectsService', function(LoadProjectsService) {
return {
template: ...
link: function(){
LoadProjectsService.postProjects()
.success(
loadProjects()
)
}
};
});
My problem consist in that I have some data in REST service and I want to get them and then send to rest of controllers. But I don't know how to do correctly because service $http.get() is perform asynchronously. I will show you piece of my code in order to better represent problem.
I created controller which is responslible for get data from REST service.
MyApp.controller("AppController", ["$scope", "$http", function($scope,$http) {
$http.get("http://localhost:8080/library/book").success(function(data) {
$scope.bookList = data;
});
$http.get("http://localhost:8080/library/author").success(function(data) {
$scope.authorList = data;
});
$http.get("http://localhost:8080/library/publisher").success(function(data) {
$scope.publisherList = data;
});
}]);
BookList, authorList, publisherList are building materials for rest of controllers.
Ok, I show other piece of code.
MyApp.service("BookListModel", function() {
this.createBookList = function(bookList, authorList, publisherList) {
var i = 0, j = 0, authorName, publisherName, bookListItems = [];
for(; i < bookList.length; i++) {
for(; j < authorList.length; j++) {
if(bookList[i].authorId == authorList[j].authorId) {
authorName = authorList[j].name;
}
}
j = 0;
for(; j < publisherList.length; j++) {
if(bookList[i].publisherId == publisherList[j].publisherId) {
publisherName = publisherList[j].name;
}
}
j = 0;
bookListItems.push({'title' : bookList[i].title, 'author' : authorName, 'publisher' : publisherName});
authorName = "", publisherName = "";
}
return bookListItems;
};
});
For example this is one of my serivces. It create book list with authors and publishers and it take three arguments and I don't know how pass data from AppController to createBookList function.
Use a factory/service to make your REST calls (don't do it in a controller).
If you're making all these calls at the same time, you can use $q.all() to combine the promises and get a single promise.
Whenever a controller gets that promise, they'll get the same data each time and your REST services will only be called once.
Your controllers just call LibraryService.getLibraryData() and handle the promise to get the data itself.
MyApp.factory('LibraryService', function($http, $q){
var service = {};
var libraryDataPromise = $q.defer();
$q.all({
books: $http.get("http://localhost:8080/library/book"),
authors: $http.get("http://localhost:8080/library/author"),
publishers: $http.get("http://localhost:8080/library/publisher"),
}).then(function(response){
libraryDataPromise.resolve({
bookList: response.books,
authorList: response.authors,
publisherList: response.publishers
});
});
service.getLibraryData = function() {
return libraryDataPromise.promise;
};
return service;
});
You can also do an angular broadcast. In your 'AppController':
....
http.get("http://localhost:8080/library/book").success(function(data) {
$scope.$broadcast('bookList-updated', data);
}
....
Then in your other controllers where you want to use the data do this:
....
$scope.$on('booklist-updated', function(event, booklist){
$scope.booklist = booklist;
});
....
Use angular services
app.service('mySharedService', function ($rootScope) {
this.bookList = [];
this.authorList = [];
this.publisherList = [];
this.setBookList = function (bookList) {
this.bookList = bookList;
};
this.setPublisherList = function (publisherList ) {
this.publisherList = publisherList ;
};
this.setAuthorList = function (authorList ) {
this.authorList = authorList ;
};
this.getBookList = function () {
return this.bookList;
};
this.getPublisherList = function () {
return this.publisherList;
};
this.getAuthorList = function () {
return this.authorList;
};
});
Make sure to pass\inject your service to your controller
MyApp.controller("AppController", ["$scope", "$http", "mySharedService", function($scope,$http) {
$http.get("http://localhost:8080/library/book").success(function(data) {
$scope.bookList = data;
mySharedService.setBookList(data);
});
$http.get("http://localhost:8080/library/author").success(function(data) {
$scope.authorList = data;
mySharedService.setPublisherList(data);
});
$http.get("http://localhost:8080/library/publisher").success(function(data) {
$scope.publisherList = data;
mySharedService.setAuthorList(data);
});
}]);
NOTE: I didn't test the code.
I have problem with the Scope of JS functions and/or Angularjs promise and $q. I looked up some examples but I did not get it at all.
In my app I have some data saved in indexeddb of my browser. In Frontend there is an input field with autocomplete function. The value of the input field goes to my angularjs Controller and calls a function. The function should return the found values. The logic of finding values from indexeddb is working fine.
The problem is that I return my array before the values are pushed into the array. So I am not sure if I need to change some stuff in JavaScript scope or to use Angularjs stuff.
Here is my Controller:
var AutocompleteController = function($scope, $http, $q) {
$scope.getCodeFromDB = function(val) {
var codes = [];
var openDbRequest = indexedDB.open('testDb', 1);
openDbRequest.onsuccess = function (e) {
var db = e.target.result;
var transaction = db.transaction("codeobjekt");
transaction.objectStore("codeobjekt")
.openCursor(IDBKeyRange.bound(val, val + '\uffff'))
.onsuccess = function (e) {
var cursor = e.target.result;
if (cursor) {
codes.push(cursor.value.code); //gets filled
console.log(cursor.value.code);
cursor.continue();
}
};
};
console.log(codes); //is empty
return codes;
};
};
Thanks in advance.
in your code you try to use an array filled after the return.
Try using the $q service provides by angular like that.
var AutocompleteController = function($scope, $http, $q) {
$scope.getCodeFromDB = function(val) {
var def= $q.defer(),
codes = [],
openDbRequest = indexedDB.open('testDb', 1);
openDbRequest.onsuccess = function (e) {
var db = e.target.result;
var transaction = db.transaction("codeobjekt");
transaction.objectStore("codeobjekt")
.openCursor(IDBKeyRange.bound(val, val + '\uffff'))
.onsuccess = function (e) {
var cursor = e.target.result;
if (cursor) {
codes.push(cursor.value.code); //gets filled
console.log(cursor.value.code);
cursor.continue();
}
else {
//cursor end
def.resolve(codes);
}
};
};
return def.promise;
};
};
And the usage
//usage
$scope.getCodeFromDB("value")
.then(function(codes) {
//codes filled
});
I am really new to angular.js. This is my first Service that I wrote. It takes a json object and updates the scope of the controller. I'm a little confused on it though...I think I am supposed to wrap the inner code of sseListener and return it as a function, but I am not sure how exactly I would write that and why I need to return it as a function.
Also, if I inject this service to several controllers, would that multiply the event listeners? I only want to have one event listener.
one#demo ~/cloudimageshare-monitoring/project/app/scripts $ cat services/sse_listen.js
angular.module('monitorApp')
.factory('sseListener', function () {
var source = new EventSource('/subscribe');
source.addEventListener('message', function(e) {
var result = JSON.parse(e.data);
event = Object.keys(result)[0];
switch(event) {
case "cpuResult":
cpuUpdate(result);
break;
}
});
}
one#demo ~/cloudimageshare-monitoring/project/app/scripts $ cat controllers/main.js
'use strict';
angular.module('monitorApp')
.controller('homeCtrl', function($scope, $location, $document) {
console.log("s");
});
angular.module('monitorApp')
.controller('cpuCtrl', function($scope) {
$scope.apiTimeStamp = "";
$scope.infoReceived = "";
$scope.last15 = "";
$scope.last5 = "";
$scope.lastMinute = "";
var cpuUpdate = function (result) {
$scope.$apply(function () {
$scope.apiTimeStamp = result.cpuResult.timestamp;
$scope.infoReceived = new Date();
$scope.last15 = result.cpuResult.metrics['1m'].data
$scope.last5 = result.cpuResult.metrics['5m'].data
$scope.lastMinute = result.cpuResult.metrics['15'].data
});
}
});
Instead of calling cpuUpdate directly (it's not clear to me how your factory gets a reference to this function), it would be better to use $rootScope.$broadcast(eventName, data), and react to the event in your controller. Also, you should return an object from factories, but since you don't need to inject this anywhere, it's best to put it in an app.run. Here's how I think your code should with the changes I mentioned:
angular.module('monitorApp').
run(function ($rootScope) { //Inject the $rootScope
var source = new EventSource('/subscribe');
source.addEventListener('message', function(e) {
var result = JSON.parse(e.data);
event = Object.keys(result)[0];
switch(event) {
case "cpuResult":
// Broadcast the event with data
$rootScope.$broadcast('$cpuResult', result);
break;
}
});
}).
controller('cpuCtrl', function($scope)){
$scope.apiTimeStamp = "";
$scope.infoReceived = "";
$scope.last15 = "";
$scope.last5 = "";
$scope.lastMinute = "";
// Need to pass the event to cpuUpdate,
var cpuUpdate = function (e, result) {
$scope.$apply(function(){
$scope.apiTimeStamp = result.cpuResult.timestamp;
$scope.infoReceived = new Date();
$scope.last15 = result.cpuResult.metrics['1m'].data
$scope.last5 = result.cpuResult.metrics['5m'].data
$scope.lastMinute = result.cpuResult.metrics['15'].data
});
};
//Listen for the event, call cpuUpdate when caught
$scope.$on('$cpuResult', cpuUpdate);
});