Use Coldfusion query resultset in AngularJS - javascript

I'm trying to use AngularJS in my cfm files to display data from cfquery resultset.
I used below code in my cfm file.I'm not able to see any output.
P.S. I'm really new to AngularJS. So if anyone can please help me out here it would be great.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html ng-app="Demo">
<head>
<link rel="stylesheet" href="/Applications/_Common/style.css" type="text/css">
</head>
<body>
<cfsetting enablecfoutputonly="Yes">
<CF_GetProjectData project_number=349246 query_name="GetProject">
<div ng-controller="DemoController">
<div ng-repeat="number in project">
{{number.project_number}} - {{number.project_name}}
</div>
<!-- <input name="imprint" type="text" size="10" ng-model="first">
<p>{{first}}</p> -->
</div>
<cfoutput>
<script language="JavaScript" src="/CFIDE/scripts/wddx.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"></script>
<script language="text/javascript">
var theProjectArray; < cfwddx action = "CFML2JS"
input = "#GetProject#"
toplevelvariable = "theProjectArray" >
</script>
<script>
var Demo = angular.module("Demo", []);
Demo.controller("DemoController", function($scope) {
$scope.project = theProjectArray;
alert(theProjectArray);
});
</script>
</cfoutput>
<cfsetting enablecfoutputonly="No">
</body>
</html>

I am not sure about Angular.js but based on the code you have posted, it seems, you need to wrap ng-controller div in cfoutput. This is because you have set enablecfoutputonly="Yes". So only the content inside cfoutput will be rendered.

I'm a CF developer that's currently learning Angular as well. First of all Angular is a MVC framework and will work for you best of you follow the rules of Separation of Concern (SoC). I know unless you are using Object Relational Mapping (ORM) in CF this is counter intuitive but it will save you so much hassle and trouble shooting later.
For your problem right now though i would
combine both script blocks.
your variable theProjectArray is defined with var so it's not
global. Are you sure it's making it into your controller?
the line toplevelvariable = "theProjectArray" > ... is the greater
than sign a type-o?
After you've done those i would console.log(theProjectArray); right after it's defined. Then console.log(theProjectArray); again in your controller to ensure it's getting passed in properly.
Just for your reference here is a very basic example of a controller and a factory in angular calling a CFC. Since i've been doing things this way the only time i use ColdFusion is to retrieve data and model it. It's simplified my code and logic quite a bit and has allowed me to do a lot more now that i'm not leaning on ColdFusion.
var myapp = angular.module("test.myapp", [])
myapp.controller("MyController", function($scope, getevent) {
$scope.myData = {};
$scope.myData.doUpdate = function(item, event) {
getevent.GetProgram(item).success(function(data, status, headers, config) {
console.log(data.DATA);
$scope.test = data.DATA;
$scope.test.DATE = new Date(data.DATA.DATESTART);
});
getevent.GetProgram(item).error(function(data, status, headers, config) {
console.log("FAILED: "+item);
alert("AJAX failed!");
});
}
});
myapp.factory('getevent', function($http){
return {
GetProgram: function(item) {
var programInfo = '/foundation/cfc/calendar.cfc?method=getevent&eventid='+item;
return $http.get(programInfo);
}
};
});

Related

How to get data from rest api which has basic authentication?

I'm trying to get data from this website through HTTP get method. This website has basic authentication. The data is in JSON format.
This is the rest api website:
(https://shoploapi.herokuapp.com/sellers)
// Code goes here
angular.module('myapp', ['myapp.controller']);
angular.module('myapp.controller', ['myapp.service'])
.controller('testController', function($scope, testService) {
$scope.posts = {};
function GetAllPosts() {
var getPostsData = testService.getPosts();
getPostsData.then(function(post) {
$scope.posts = post.data;
}, function() {
alert('Error in getting post records');
});
}
GetAllPosts();
});
angular.module('myapp.service', [])
.service('testService', function($http) {
//get All NewsLetter
this.getPosts = function() {
return $http.get('https://shoploapi.herokuapp.com/sellers');
};
});
angular.module('myApp', ['base64'])
.config(function($httpProvider, $base64) {
var auth = $base64.encode("bhupendra7:ice123age456");
$httpProvider.defaults.headers.common['Authorization'] = 'Basic ' + auth;
});
<!DOCTYPE html>
<html>
<head>
<script data-require="angular.js#1.5.0" data-semver="1.5.0" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.0/angular.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-base64/2.0.5/angular-base64.js"></script>
<link rel="stylesheet" href="style.css">
<script src="script.js"></script>
</head>
<body ng-app="myapp">
<h1>Hello Plunker!</h1>
<div ng-controller="testController">
<div>
<ul>
<li ng-repeat="post in posts">
{{post.careof}} {{post.district}} {{post.gender}} {{post.name}}
</li>
</ul>
</div>
</div>
</body>
</html>
Here's the link to my Plunker:
(https://plnkr.co/edit/7pqljm?p=preview)
Can anyone help?
There are 2 problems in your code.
1. You have a typo
In angular.module('myApp', ['base64']), change to module name to myapp
2. The way you have injected your myapp.controller to myapp module
Change it to angular.module('myapp', []); You will also need to reorder your code. Check out the Plunker I have created for you.
Even if you fix the above two problems, you will still face a CORS problem from Heroku. Depending on your server-side technology (NodeJS, Rails etc.), you will need to enable it from the server to be able to communicate with your app. You can also look in to JSONP with AngularJS
Hope this helps

REST call in AngularJS does not display record

This is my first AngularJS project. I followed this website to create a simple html to display a single record by calling restful services. The rest works with the url "http://localhost:8080/api/seqs/fdebfd6e-d046-4192-8b97-ac9f65dc2009".
Here is my html:
<html ng-app="cgApp" ng-controller="CgseqCtrl">
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.5/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.5/angular-resource.js"></script>
<script src="../js/controller.js"></script>
</head>
<body>
<div>
<hr>
<h2>{{seq.analysisId}}</h2>
<h2>{{seq.library}}</h2>
</hr>
</div>
</body>
</html>
I defined the resource in a service js
//service.js
angular.module('cgApp', ['ngResource'])
.factory('CgseqService', function ($resource) {
return $resource('http://localhost:8080/api/seqs/fdebfd6e-d046-4192-8b97-ac9f65dc2009',
{get: {method: 'GET'}
});
});
The controller:
//controller.js
angular.module('cgApp', ['ngResource'])
.controller('CgseqCtrl', ['CgseqService', '$scope', function (CgseqService, $scope)
{
$scope.getSeq = function(response) {
CgseqService.get(function(data) {
$scope.seq = data;
});
};
}]);
When I started my http server with Node.js and typed the url in the browser, nothing is displayed. What did I do wrong?
Several errors.
You didn't load your factory code. It looks like you only loaded your controller.js (I'm assuming your factory code is in a different file since in your example you commented it as //service.js):
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.5/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.5/angular-resource.js"></script>
<script src="../js/controller.js"></script>
</head>
np-controller should say ng-controller:
<html ng-app="cgApp" np-controller="CgseqCtrl">
You also never called your $scope.getSeq function:
$scope.getSeq = function(response) {
CgseqService.get(function(data) {
$scope.seq = data;
});
};
You should call $scope.getSeq() somewhere to actually invoke it.

Angular.js - Convert string with special characters and numbers into Array and display with ng-repeat

I am new to angular.js and I'm having an issue with converting string into array and displaying it with ng-repeat, so far i got this custom filter from a stackoverflow question and the codes are:
JS:
var app = angular.module('globalModule', [])
app.controller("SampleController", function($scope){
$scope.data = "123abc123";
});
app.filter("spaceBreak",
function () {
return function ( value ) {
if( !value.length ) return;
return value.split("");
}
});
HTML:
<body ng-controller="SampleController">
<h4 id="id_{{$index}}" ng-repeat="value in data | spaceBreak"><span ng-bind="value"></span></h4>
</body>
My problem is, it converts and display properly if it is an alphabet(abc) or a number(123) alone, and if combined (abc123) or (123abc) still good, but if the data is number+alphabet+number (123abc123) it doesnt show anymore in ng-repeat. I am really lost and really need help. Hope someone can lend me an answer.
I think what you are looking for is the track by $index functionality. You code errors out because you have duplicates in your $scope.data. That filter isn't really doing anything for you, so you can just ng-repeat through your $scope.data string.
var app = angular.module('globalModule', [])
app.controller("SampleController", function($scope){
$scope.data = "123abc123";
})
<!DOCTYPE html>
<html ng-app="globalModule">
<head>
<script data-require="angular.js#1.5.0" data-semver="1.5.0" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.0/angular.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body ng-controller="SampleController">
<h4 id="id_{{$index}}" ng-repeat="value in data track by $index"><span ng-bind="value"></span></h4>
</body>
</html>

Preload an angular route for instant viewing

I am relatively new to angular and here is what I am trying to do:
I am trying to pre-compile angular templates into a view so that they can be shown instantaneously when the navigation event to the view occurs.
I am trying mock some kind of a navigation controller behavior for my app where the views preload or stack up and don't show in the SPA until their routes are active.
I did some research and $templateCache might not be something that would work for me since it seems to be only prefetching the template, viz. the uncompiled view (as per my limited understanding of angular), but what I am looking for is the "compiled version"; that is, the result of a $scope applied to a template.
Currently, the app's templates and controllers are linked through $routeProvider and ng-view constructs.
Minimal code skeleton:
JS:
var app = angular.module('airfiApp', ['ngRoute']);
app.config(function($routeProvider) {
$routeProvider
.when('/', {
templateUrl: 'views/home.html',
controller: ''
})
.when('/shop', {
templateUrl: 'views/shop.html',
controller: 'ShopController'
})
.otherwise({
redirectTo: "/index.html"
}))
});
app.controller('ShopController', ['ImageFetchService', function(ImageFetchService) {
ImageFetchService.get().then(function(images) {
$scope.images = images;
});
}]);
app.factory('ImageFetchService', ['$q', '$http', function($q, $http) {
var def = $q.defer();
//basically get product docs with id products:name-of-product
var couchdbURL = 'http://username:password#localhost:5984/db_name/_all_docs?startkey="products"&endkey="products\uffff"';
$http.get(couchdbURL).then(function() {
//do some processing and send back array of objects called 'images'
/* images =
[
{
... product information... ,
src: http://couchurl/db_name/product1/attachment_name
},
{
... product information... ,
src: http://couchurl/db_name/product2/attachment_name
}
.
.
.
]
*/
def.resolve(images)
});
}]);
HTML:
//index.html
<!DOCTYPE html>
<html>
<head>
<script src="/Scripts/angular.js"></script>
<link href="/Content/bootstrap.css" rel="stylesheet"/>
</head>
<body>
<!-- some home page html -->
<section ng-view> </section>
</body>
</html>
//shop.html
<div ng-repeat = " img in images">
<img ng-src="img.src" alt="img.productName" />
</div>
I really don't think you need to compile the template manually - angular will do this for you. If you really insist, you can compile any template against any scope using $compile:
$compile( element.contents() )( scope );
What I really think you're after is loading of inline template. This question shows how it is done.
A couple things you can do to easily speed up how fast a view is rendered, first thing is you can pre-load the data by calling a pre-load method in a service, during the run phase of the App. Example
//service that has a preload function that stores an http result in memory
app.service('myService', function($http){
var data;
this.getData= function(){
return $http.get('dataUrl')
.success(function(data, status, headers, config) {
return data;
})
};
// calls get data and stores result in memory
this.preloadData = function(){
this.getData().then(function(data){
data = data;
});
};
// returns in memory result
this.getPreloadedData = function(){
return data;
};
});
// call preload in run block
app.run(function(myService){
// preloads data from service
myService.preloadData();
});
// get data from in memory
app.controller('TestCtrl', function($scope, myService) {
$scope.data = myService.getPreloadedData();
});
The second thing you can do is store the template in $template cache rather than fetching it form a http request, you can do this in the run block as well, and if you using gulp or grunt there are some great plug ins that provide a better way of doing this
app.run(function($templateCache){
// cache template
var tempalate = '<h2>hello world</h2>'
$templateCache.put('test.html', tempalate);
});
here is a plunk that goes into better detail and shows more examples
http://embed.plnkr.co/DSeWLVNoV2Fe0SJI3Bwa/preview
This does exactly preload the route but it will help performance :)

Updating HTML element outside of ng-view

I have the below HTML on a page:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" ng-app="myCart">
<head>
<title>AngularJS Shopping Cart</title>
<link href="css/jsonstore.css" rel="stylesheet" />
</head>
<body>
<div id="container">
<div id="header">
<h1>The JSON Store</h1>
<div class="cart-info">
My Cart (<span class="cart-items">{{item.basketCount}}</span> items)
</div>
</div>
<div id="main" ng-view>
</div>
</div>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.0.4/angular.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.0.4/angular-resource.js"></script>
<script src="js/routing.js"></script>
<script src="js/dataresource.js"></script>
<script src="js/basketinfo.js"></script>
<script src="js/index.js"></script>
<script src="js/detail.js"></script>
</body>
</html>
The div "main" gets replaced by HTML templates by my routes however I would like to update the header section with a shopping basket count.
I have tried model binding it as shown in the HTML and below:
function DetailController($scope, item, basketDetail) {
$scope.item = item;
$scope.item.basketCount = basketDetail.getCount();
//more code
}
I've also tried just injecting the service and calling it from the HTML. Both ways do not do anything.
Can someone help please?
Thanks
Your header div is really a view, just like the other views you've defined for use with ng-view. Someday, you might want to show more than just a basketCount model in that header view. But the fact that you are projecting even one piece of model data into that header section makes that section a view. So, I would recommend that be given its own $scope to project that model, hence its own controller.
What remains then is where to put the basketCount model? And we must consider that multiple views may allow the user to do something that need to affect that model. Angular's normal answer for "many need access" is dependency injection. So, I would put the basketCount model into a service. Views/controllers that need access to it can inject it. Someday your app may have additional views that don't need access to these models, so those views would not inject the service.
Potentially, the entire basket could be modeled in this service:
app.factory('basketService', function() {
return {
items: [],
itemCount: 0,
...
}
});
function HeaderCtrl($scope, basketService) {
$scope.basket = basketService;
...
}
function DetailCtrl($scope, basketService) {
$scope.basket = basketService;
...
}
<div id="header" ng-controller="HeaderCtrl">
<h1>The JSON Store</h1>
<div class="cart-info">
My Cart (<span class="cart-items">{{basket.itemCount}}</span> items)
</div>
You'll need to inject $rootScope, then update it:
function DetailController($scope, $rootScope, basketDetail) {
$rootScope.item = $rootScope.item || {};
$rootScope.item.basketCount = basketDetail.getCount();
//more code
}
There are a lot more ways to do this, but this is my first suggestion, because it's probably the easiest.
EDIT: per your request, other ways to do this...
You could use $parent to push to your parent scope. The upside is it's pretty quick and clean... the downside is it's a little sloppy in that one of your controllers makes assumptions about what it's parent is to some degree (but that's still not terrible, really):
{{item.basketCount}}
<div ng-controller="InnerCtrl">
</div>
function InnerCtrl($scope, basketDetail) {
$scope.$parent.item = $scope.$parent.item || {};
$scope.$parent.item.basketCount = basketDetail.getCount();
}
Then there's the method #asgoth mentioned above where you use nested controller and a method on the parent scope to update the parent scope. Valid, but like my other solution in this "other ways to do it" section, it relies on assumptions made about the controller's container, and it also relies on you creating an additional controller.
Finally, you could create a service. Now services aren't generally used this way, but you could use one this way.. Where you could take your basketDetail service, and use it to pass the value back and forth. Like so:
app.factory('basketDetail', function() {
return {
items: { basketCount: 0 },
getCount: function() {
//return something here
return 123;
}
}
});
function FooCtrl($scope, basketDetail) {
$scope.items = basketDetail.items;
$scope.items.basketCount = basketDetail.getCount();
}
function BarCtrl($scope, basketDetail) {
$scope.items = basketDetail.items;
}
<div ng-controller="FooCtrl">
{{items.basketCount}}
</div>
<div ng-controller="BarCtrl">
{{items.basketCount}}
</div>
This works because the $scope in both controllers is keeping a reference to the same object, which is maintained by your basketDetail service. But again, this isn't really the recommended way.
All of that said: $rootScope, IMO is most likely what you're looking for.
It doesn't require the creation of an additional controller.
It doesn't require the creation of any additional function references.
Will not cause the creation of any additional parent/child Scope nesting and subsequent watches.
No real need for $rootScope. Create a parent controller (e.g. RootController) with a function on its scope. The child scopes will automatically inherit it:
<div id="container" ng-controller="RootController">
...
function RootController($scope) {
$scope.item = {};
$scope.setBasketCount = function (detail) {
$scope.item.basketCount = detail.getCount();
}
}
In your detail controller you just use the setBasketCount() function:
function DetailController($scope, item, basketDetail) {
$scope.item = item;
$scope.setBasketCount(basketDetail);
//more code
}

Categories

Resources