I'm facing an issue while working with Visualforce remoting and angularjs. Whenever I'm putting my controller code in separate js Static resource, my code doesn't work. Please help me in figuring out this.
My Visualforce page
<apex:page controller="ApexRemoteActionPageController" docType="html-5.0">
<html>
<body>
<div class="bootstrap" ng-app="ngApp" ng-controller="ContactCtrl" >
<h1 align="center">Click The Button</h1>
<button ng-click="getContacts()" class="btn btn-lg btn-default btn-block">Get Contacts</button>
<p>
<ul>
<li id="{{current.Id}}" ng-repeat="current in contacts" ng-class-even="'rowEven'">{{current.Name}}</li>
</ul>
</p>
</div>
<apex:stylesheet value="//cdn.jsdelivr.net/webjars/bootstrap-sf1/0.1.0-beta.6/css/bootstrap-namespaced.css"/>
<apex:includeScript value="//ajax.googleapis.com/ajax/libs/angularjs/1.3.0-beta.11/angular.min.js"/>
<apex:includeScript value="{!$Resource.ContactCtrl}" />
</body>
</html>
</apex:page>
My Controller Static Resource
<script>
var ngApp= angular.module("ngApp", []);
ngApp.controller("ContactCtrl", ["$scope", function($scope)
{
$scope.contacts = [];
$scope.getContacts = function() {
ApexRemoteActionPageController.myContacts(function(result, event) {
$scope.contacts = result;
$scope.$apply();
});
}
}]);
</script>
My Apex Controller
global class ApexRemoteActionPageController {
#RemoteAction
global static List<Contact> myContacts()
{
return [select id, name, email from Contact Order By LastModifiedDate DESC LIMIT 30];
}
}
Whenever I put my controller logic in same Visual Force page it works, but when i move my controller script to separate js Static resource it doesn't.
Your controller static resource is a Javascript file and as such does not need <script> tags. Remove these and I believe your static resource will work as intended.
More detail: If you use <script> tags in your js file, you will end up with markup that nests the script tags and I don't think that will work for you. This is because <includeScript> renders to a script tag in the HTML markup.
I finally found an answer. Yes part of the problem is using <Script> tag in static resource which needs to be removed, but the real problem was not placing namespace prefix before controller when placing a remoting call.
ApexRemoteActionPageController.myContacts(function(result, event)
needs to be
namespaceprefix. ApexRemoteActionPageController.myContacts(function(result, event)
Namespace prefix will not be set by default in Developer Edition, we have to navigate to ....Search bar on leftn hand side in dev account and search for create package ...go to packages and enable Managed package option ...which will give us option to set a namespace prefix for our entire account (classes.controllers...etc) and then come to javascript static resource and put your namespace before controller.methodname and thats it..
Related
So I have a simple application AngularJs and Spring mvc. I have a controlller that mapped to the angularJs page and I have this code in a jsp page :
<div ng-app="myApp" ng-controller="myCtrl">
<p>The name is <span ng-bind="person.lastName"></span></p>
{{ lastName }}
</div>
<script src="applications.js"></script>
<script src="controllers.js"></script>
application.js :
var app = angular.module("myApp", []);
controllers.js :
app.controller("myCtrl", function($scope) {
$scope.firstName = "John";
$scope.lastName= "Doe";
});
when I run this with Pivotal it dosn't run, but when I access the file directly within my browser it works like a charm, Someone care to explain pls ?
Thank you.
EDIT
WebConfig.java :
public class WebConfig extends WebMvcConfigurerAdapter {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**")
.addResourceLocations("/resources/");
}
#Override
public void configureDefaultServletHandling ( DefaultServletHandlerConfigurer configurer )
{
configurer.enable();
}
}
resources folder :
The URL : http://localhost:8080/gestionprojet/Project/angularjs
My Controller :
#RequestMapping("/angularjs")
public String getAngularJs() {
return "AngularJs";
}
First of all, your files are under /WEB-INF/resources, but you have configured spring to load static resources from /resources. So they can't be served at all. The config should be
registry.addResourceHandler("/resources/**")
.addResourceLocations("/WEB-INF/resources/");
The URL of your page is
/gestionprojet/Project/angularjs
Your page tries to load the script using the relative path
applications.js
So the corresponding absolute path where the browser looks for the JS files is
/gestionprojet/Project/applications.js
which doesn't match with the URLs you choose to serve static resources from. Assuming /gestionprojet is the context path of the application, the absolute URL should be
/gestionprojet/resources/applications.js
So the source code in the JSP should thus be
<script src="${pageContext.request.contextPath}/resources/applications.js"></script>
I am trying to get ng-route working with a google-apps-script web app. I have managed to get basic angular.js functionality working with google-apps-script, but I can't seem to get ng-route to work. I have placed ng-view tags inside a page and have included a separate JavaScript page that contains the routeProvider function.
The ng-view never gets rendered and as far as I can make out the routeProvider does not get called.
Can anyone offer any advice on using ng-route with google-apps-script or suggest another way of rendering a partial html page with google-apps-script
Any answers greatly appreciated.
Have simplified my code and added below:
Code.gs
function doGet(e) {
var template = HtmlService.createTemplateFromFile('Index');
// Build and return HTML in IFRAME sandbox mode.
return template.evaluate()
.setTitle('Web App Window Title')
.setSandboxMode(HtmlService.SandboxMode.IFRAME);
}
function getScriptUrl() {
var url = ScriptApp.getService().getUrl();
return url;
}
index.html
<!-- Use a templated HTML printing scriptlet to import common stylesheet. -->
<?!= HtmlService.createHtmlOutputFromFile('Stylesheet').getContent(); ?>
<html>
<body ng-app="myApp">
<h1>NG View</h1>
<ng-view></ng-view>
<p>angular check {{'is' + 'working!'}}</p>
<? var url = getScriptUrl();?>
<p id="urlid"><?=url?></p>
</body>
</html>
<!-- Use a templated HTML printing scriptlet to import JavaScript. -->
<?!= HtmlService.createHtmlOutputFromFile('JavaScript').getContent(); ?>
Javascript.html
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src="https://code.angularjs.org/1.3.15/angular.js"></script>
<script src="https://code.angularjs.org/1.3.15/angular-route.js"> </script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css" rel="stylesheet">
<script>
angular.module('myApp', ['ngRoute'])
.config(function($routeProvider){
console.log('routeProvider config');
var url = document.getElementById("urlid").innerHTML;
console.log('routeProvider config->' +url);
$routeProvider.when("/",
{
templateUrl: url+"?page=_app.html",
controller: "AppCtrl",
controllerAs: "app"
}
);
})
.controller('AppCtrl', function() {
var self = this;
self.message = "The app routing is working!";
});
</script>
_app.html
<div>
<h1>{{ app.message }}</h1>
</div>
When this runs angular check {{'is' + 'working!'}} works fine, but the ng-view does not get rendered the java console shows:
Error: [$sce:insecurl] Blocked loading resource from url not allowed by $sceDelegate policy.
The first obstacle is "sce"
$sce is a service that provides Strict Contextual Escaping services to AngularJS.
Refer link https://docs.angularjs.org/api/ng/service/$sce#trustAsResourceUrl
For the purpose of investigation, I disabled sce (this is not recommended, though)
$sceProvider.enabled(false);
Now the error is shifted to XMLHttpRequest cannot load... No 'Access-Control-Allow-Origin' header is present on the requested resource.
XHR requests to the Google Apps Script server are forbidden
Refer link https://developers.google.com/apps-script/guides/html/restrictions
Google Apps is delivering the files from a different origin than the scripts.google.com and angular js client code is not able to fetch the partial htmls from the same origin.
I guess approach of ng-view is not feasible given the restrictions placed by google apps.
Here is the final modified code
<script>
angular.module('myApp', ['ngRoute'])
.config(function($routeProvider,$sceProvider){
$sceProvider.enabled(false);
console.log('routeProvider config');
var url = document.getElementById("urlid").innerHTML;
console.log('routeProvider config->' +url);
$routeProvider.when("/",
{
templateUrl: url+"?page=_app.html",
controller: "AppCtrl",
controllerAs: "app"
}
);
})
.controller('AppCtrl', function() {
var self = this;
self.message = "The app routing is working!";
});
</script>
There has been some time since the question, but I'll post a reply either way.
If your partial html page is not too complicated and big, you can use template instead of templateUrl in the routeProvider, plus create a variable with the html you want to show. Something like this below:
var partial_page = "<span>partial page</span>"
$routeProvider.when("/",
{
template: partial_page,
controller: "AppCtrl",
controllerAs: "app"
}
It worked for me, but I wouldn't advise doing so for a complicated partial page as it may become difficult to read the code
I am new to angularjs, and I have an jquery background.
I want to compile json from the server into an element with an template.
What I now have for so far is:
The template:
<script type="text/ng-template" id="/tiles.html">
<div ng-repeat="tile in tiles">
{{tile.name}}<img ng-src="tile.src" />
</div>
</script>
The button for displaying the content:
<button ng-click="imageOptions.addFromList()">+ Add Image from list</button>
The function:
$scope.imageOptions.addFromList = function (){
$http
.get('/json/Tiles/get')
.success(function(data){
$scope.tiles = data;
console.log(data);
})
.error(function(data){
console.log("something did go wrong");
});
$(".prompt").html('<div ng-include src="/tiles.html"></div>');
};
The placeholder:
<div class="prompt"></div>
The placeholder will be used many times with also other content.
So I can not just type the html from the .html() argument. Like this:
<div class="prompt"><div ng-include src="/tiles.html"></div></div>
When I inspect the .prompt div it will stay uncompiled
The first thing you should do is remove jQuery library from your app while you get familiar with angular methodology.
There is no need to use html() method when all you need to do is include your template through a variety of different ways in your html source.
If the data isn't already available for ng-repeat it will simply fail quietly and do nothing. Then when the data is available it will respond automatically.
You could simply do:
<div class="prompt" ng-include src="/tiles.html"></div>
Or you could make a simple directive that will accomplish the same thing .
app.directive('prompt', function() {
return {
restrict: 'C',/* use for "class" */
templateUrl: '/tiles.html'
}
});
Simply change this
<div ng-include src="/tiles.html">
to this
<div ng-include src="'/tiles.html'">
While coding your single page application in angularjs, ideally there should not be any need for you to first get a reference to an element and then perform some action on it (You may think of this as the first step of switching from a jquery background to angularjs domain).
To achieve complete separation of model, view and controller you should just define your templates and controllers accordingly. These mappings and references should be managed by angularjs on its own.
As correctly mentioned above you should not be using .html() method of jquery. If you have included jquery in your document, it will be internally used by angularjs, but, including jquery should not be mandatory for using angularjs.
ng-repeat and ng-include also create a separate scope, so you may want to take care of those as well in future.
For your query, you may reference the template by including extra quotes in ng-include as:
<div class="prompt">
<div ng-include src="'tiles.html'"></div>
</div>
http://jsfiddle.net/PKKp8/
I have a tabbed navigtion in my webapp that looks like this
Now I want to Change the directive each time the user clicks on one of the Navigation points. My Idea was to init the page with the first template.
$scope.currentDirective = $compile('<div order-Sale></div>');
Then when the user clicks on a tab, I wanted to change and compile the content again with a new directive in it. But for some reason this is not working. How would you proceed in order to archive this dynamic content loading? I really want to only load the content on necessary need and not just to show or hide it. I think using directives is the right way to go for it, but I'm a but stuck at the implementation... Someone any pointer ? (I don't want to use any jQuery)
What I tried [Edit]:
The controller.js
app.controller('pageController',['$scope','$compile', function($scope, $compile){
var templates = ['<div first-template></div>','<div second-template></div>'];
$scope.currentTemplate = $compile(templates[0]);
$scope.changeTemplate = function(id) {
$scope.currentTemplate = $compile(templates[id]);
};
}]);
The HTML
<div ng-controller="pageController">
<li>
<a ng-click="changeTemplate('1')">Change Template</a>
</li>
{{currentTemplate}}
</div>
UPDATE
$compile returns a linking function not a value, you cannot just bind it to your template with interpolation.
You should use ngBindHtml instead of regular bindings ( ngBind & {{ }} ).
ngBindHtml does compiling, linking and watching all out-of-the-box.
With ng-bind-html-unsafe removed, how do I inject HTML?
Here is a plunker
app.controller('pageController',['$scope','$compile','$sce', function($scope, $compile, $sce){
var templates = ['<div>first-template</div>','<div>second-template</div>'];
$scope.currentTemplate = $sce.trustAsHtml(templates[0]);
$scope.changeTemplate = function(id) {
$scope.currentTemplate = $sce.trustAsHtml(templates[id]);
};
}]);
The markup:
<div ng-controller="pageController">
<button ng-click="changeTemplate('1')">Change Template</button>
<div ng-bind-html="currentTemplate"></div>
</div>
For more robust dynamic content loading you have two good alternatives:
ngRoute from angular team.
ui-router from angular-ui team.
If you want to change and compile the content again, well that's exactly what ng-view/ ui-view directives already do for you.
Why not just use a directive:
You probably need to load a different template (html partial) for each tab.
You probably need to change the url based on the tab (and vice versa)
You probably need to instantiate a different controller for each tab.
ngRoute and ui-router come with their own directives.
You can implement your own route module if you want but that's more than just a directive.
I'm pretty sure it's something stupid again. I'm learning angularjs so I don't get the full scope yet but I'm getting there. I tried everything and really searched for anything I could find but nothing seemed to work.
I'm trying to do a ng-class="..." in my layout file but the expression is set in my controller but somehow it's not rendered. It is rendered when I put it in my ng-view file. I get that he only renders part of the file but I want him to render the ng-class on ng-view as well. Is this possible or is it easier to just put in a div inside the partial html file.
Simple html file
<body>
<ng-view ng-class="{ 'splash': splash=='splash' }"></ng-view>
</body>
My controller
angular.module('xxx.splash')
.controller('IndexCtrl', function($scope, $rootScope, config) {
$rootScope.splash = 'splash';
$scope.login = function(e) {
alert('Soon. How soon? Very soon.');
}
});
When you define a variable in the root scope, you can't access it in the same way as you define it in the local scope. $rootScope variables can be accessible in the AngularJS templates using $root.<variableName>, so your HTML file should be changed to this:
<body>
<ng-view ng-class="{ 'splash': $root.splash=='splash' }"></ng-view>
</body>
You can see the diffrence of $scope and $rootScope in this demo