AngularJS with Salesforce - angularjs

Need help in knowing how to use AngularJS in Salesforce Lightning and VisualForce pages?
I do know that it has to be used using static resource but need step by step details in using it.

Well, when talking about AngularJS, I believe you are talking about the version 1.x, because the version 2.0, which is currently 6.0 needs to be used in a different way compared to the earlier version.
For Angular 1.x, I am listing down the steps here:
The very first step is to download the latest version of AngularJS. You can get that here.
https://angularjs.org/
Zip the AngularJS file and create a Static Resource, so that you can reference it in your pages. In case, you want to know how to create a static resource in Salesforce, refer SF documentation.
https://developer.salesforce.com/docs/atlas.en-us.pages.meta/pages/pages_resources_create.htm
(You also have an option of directly referencing the CDN file in your VF pages, however, it is recommended that you should go for Static resources.)
Now, to get AngularJS in action, you have to do something called as “bootstrapping” your app.
This can be done in 2 ways:
Use “ng-app” directive. (NOTE:You can only have one ng-app directive in your HTML document. If more than one ng-app directive appears, the first appearance will be used.)
And the second way is manual bootstrapping. You can refer to this blog to know more about it.
http://blogs.quovantis.com/process-to-use-manual-bootstrapping-in-angularjs-with-examples/
You can use the following code to see manual bootstrapping in action.
<apex:page showHeader="true" sidebar="true">
<apex:includeScript value="{!URLFOR(<your-static-resource-name>,'angular.min.js')}">
<div id="demo" ng-controller="demoAngularController">
{{testVar}}
</div>
<script>
var demoModule = angular.module('demo', []);
demoModule.controller('demoAngularController', function ($scope) {
$scope.testVar = 'Prem';
});
angular.bootstrap(document.getElementById("demo"),['demo']);
</script>
Make sure you replace the static resource name with actual name that you created in the system.
I have added a code snippet as well.
var app = angular.module('demo', []);
app.controller('demoAngularController',function MyController($scope) {
$scope.testVar = 'Prem';
});
angular.bootstrap(document.getElementById("demo"),['demo']);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div id="demo">
<div ng-controller='demoAngularController'>
<h1>Hello, {{ testVar }}!</h1>
</div>
</div>
For Angular 2.0
In case, you want to learn the usage of Angular2.0 (or Angular6.0 as known currently), you may look at this tutuorial and let me know your feedback.
https://premjpal.wordpress.com/2018/09/06/getting-started-with-angular6-in-salesforce/
Happy coding!

Related

HTML and JAVASCRIPT Editor in Angularjs

I have an angularjs 1.5.8 application created using Jhipster.
For my website I want to make a HTML and JAVASCRIPT editor. Need to allow user to write HTML Code but JAVASCRIPT also.
Using this library I know I can achieve the follow.
https://github.com/incuna/angular-bind-html-compile
1: Bind HTML Code.
2: Bind Angular code if present in HTML
Eg: <h1>{{$scope.test}}</h1>
Would render correct value in the scope.
But what about something like this in the html
<script>
console.log($scope);
</script>
I get a $scope not defined error, somehow the $scope value is not available in the script tag.
If anyone curious that why I need to do this because we want to provide users of the application to create there own Angularjs Forms.
I solved using ng-include, here is the example source.
I wanted to do two things.
1: Make ng-include work from a scope variable which will contain html and javascript.
2: In the included string if I have a script tag I wanted it to render correct in the ng-include.
To achieve the #1 I did the following.
Used $templateCache service.
Sample code.
$templateCache.put('template-form', vm.html + vm.script);
For point #2
I made sure the script tag is structured in the following way.
<script>
(function() {
'use strict';
angular.module('myApp').controllerProvider.register('AppTemplateController',AppTemplateController);
AppTemplateController.$inject = ['$scope'];
function AppTemplateController($scope){
// WRITE YOUR CODE IN THIS CONTROLLER
// YOU CAN WRITE YOUR VARIABLES/FUNCTIONS HERE.
// MAKE SURE TO CALL THE method "vm.submitForm", to submit your form and pass the form object.
};
})();
</script>
This way you can inject a controller.
My requirement was very very specific to my projecct, I am not sure if others who did not face this issue even would understand what I am talking about. But for those who do face it, I hope you it helpful

How can I integrate Angular with an existing JavaScript architecture that makes heavy use of clone?

I'm working on a legacy web application (well, I say legacy, it's from about a year ago and programmed in Knockout and JQuery), and I'd like to program a new interface in Angular, with a view to replacing all other portions of the application with Angular as we go on as this is a very complicated user interface that isn't horrible enough to warrant a complete rewrite.
I would like to integrate Angular code with the existing codebase, and for my first controller I'd like to program a pop-up box which allows the user to modify some data. I created a div with a data-ng-controller of "MyController" and it all works well, but I don't seem to be able to create many of them.
If we have multiple controllers, i.e:
<div data-ng-controller="MyController">
</div>
<div data-ng-controller="MyController">
</div>
Both instances of MyController would have their own scope which is definitely want, and it works totally fine for my app this way. But unfortunately, my system works on cloning a div for every instance of the pop-up box:
<div data-ng-controller="MyController" id="myWindow">
</div>
<script>
function showWindow()
{
var dialog = $("myWindow").clone();
dialog.show();
)
</script>
When showWIndow() is called, the reference to MyController seems to travel along with it, so I don't get two instance of MyController.
I can't seem to find how to create multiple instances of the same controller and attach it though.
For example, I thought this might work:
<div id="myWindow">
</div>
<script>
function showWindow()
{
var dialog = $("myWindow").clone().setupDialog();
dialog.attr("data-ng-controller", "MyController");
dialog.show();
)
</script>
But unfortunately, the breakpoint in MyController never gets hit. I suspected that this might be due to the order of attaching, but reversing the call to attr() and show had no effect:
var dialog = $("myWindow").clone().setupDialog();
dialog.show();
dialog.attr("data-ng-controller", "MyController");
I assume that there's some method in the angular library somewhere that allows me to instantiate a controller and attach it to an element. About an hour of googling has yielded nothing but I can't believe that something like this doesn't exist somewhere.
The HTML must be compiled to make angular directives work.
Usually the compile steps are done by angular behind the scenes (ng-app, bootstrap). Ng-repeat does it for example when creating new templates throug iterations.
But here, angularJS doesn't "know" you have DOM nodes to compile and you must do it manually.
You must learn about compile on angular, here are the docs:
reference api for $compile (the last exemple on this page is the one that helped me the most)
reference guide for compiling on angular
Here's what you might have to do (not sure because I haven't a deep knowledge on this):
create a scope for your duplicated widget
compile the template (where angular look dom markup for directives and expressions)
link the compiled template to the created scope
I think I've found it, but I don't know if this is necessarily the correct way to do it.
I firstly removed the data-ng-app property from my <body> element. I then applied the data-ng-controller programatically and called angular.bootstrap to specify the module I wanted to link to the element:
function showWindow()
{
var dialog = $("myWindow")
.clone()
.attr("data-ng-controller", "MyController")
.setupDialog();
angular.bootstrap(dialog, ["MyModule"]);
dialog.show();
)
It certainly works for me, although I'm not sure if there are side-effects to doing this that won't be apparent until later.

How to run two separate Angular js apps in the same page

New to Angular. I feel like I'm missing something obvious: Shouldn't I easily be able to run to separate AngularJs apps (modules) in the same html page? Something like this:
<section ng-app="HelloWorldApp" ng-controller="HelloWorldController">
Hello {{name}}!
</section>
<br />
<section ng-app="MyNameIsApp" ng-controller="MyNameIsController">
My Name is {{FirstName}} {{LastName}}!
</section>
Javascript:
var HelloWorldApp = angular.module('HelloWorldApp', []);
HelloWorldApp.controller('HelloWorldController', function($scope) {
$scope.name = 'World';
});
var MyNameIsApp = angular.module('MyNameIsApp', []);
MyNameIsApp.controller('MyNameIsController', function($scope) {
$scope.FirstName = 'John';
$scope.LastName = 'Smith';
});
This only runs the first module, while the second doesn't appear to do anything. I want to do this so that I can build reusable, encapsulated directives for multiple pages that don't have to name their modules the same thing.
Live Example: http://plnkr.co/edit/cE6i3ouKz8SeQeA5h3VJ
We ended up building small hierarchy of modules, however my original question can done, with just a bit of work (see below).
It is possible, but it requires a little bit coding by hand. You need to bootstrap the angular apps on your own. Don't worry, it is not that complicated
Do not add ng-app attributes in your HTML
Make sure you can fetch the DOM elements holding the app
When DOM is loaded you need to start the apps on your own: angular.bootstrap( domElement, ['AppName']);
Fork of you plunker which works: http://plnkr.co/edit/c5zWOMoah2jHYhR5Cktp
According to the Angular docs for ngApp:
Use this directive to auto-bootstrap an application. Only one
directive can be used per HTML document. The directive designates the
root of the application and is typically placed at the root of the
page.
Seems it's by design.
You can specify any nested apps in the module def of the main one.
angular.module("myapp", ['statusapp', 'tickerapp']).controller(....
and in a separate file, you have the other apps defined. We're using a template engine which hides some of this, but you'll end up with HTML that contains nested ng-apps and javascript for each one that defines the module/controller. The code above is the trick to getting more than one bootstrapped.

angularjs controller executes twice

A similar question was asked here but it did not help me.
I am learning angularjs and I noticed the controller is executed twice.
I have a very simple fiddle example that shows the behavior here
I built the example as I was learning about services and at first I thought it was the injecting of the services into the controller but I commented all the code related to the services and still the controller is executed twice.
My example works but I am afraid I am doing something wrong.
<div ng-app="MyApp">
<div ng-controller="MyCtrl">
{{data1}}
</div>
</div>
var app = angular.module('MyApp', [])
app.service('Service1', function(){
return {
ajxResponse1: 'dataFromService1'
};
});
function MyCtrl($scope, Service1){
alert('Entering MyCtrl');
$scope.data1 = Service1.ajxResponse1;
alert('Exiting MyCtrl');
}
One possible source is this: if you are using Routing and specify the controller in routes - you must not specify it in template that the route uses. We had that problem when this was overlooked.
Your controller was running twice in the fiddle because angular is referenced twice (once via the Frameworks & Extensions drop down and another as an External Resource).
See this updated fiddle where I removed the External Resource and the alerts only show up once.
The code remains unchanged:
function MyCtrl($scope, Service1, Service2, Service3){
alert('Entering MyCtrl');
$scope.data1 = Service1.ajxResponse1;
$scope.data2 = Service2.ajxResponse2;
$scope.data3 = Service3.ajxResponse3;
alert('Exiting MyCtrl');
}
I had a similar problem and it was due to slashes in my routing.
I had something like /post{slug:[a-z0-9-]*/} for my route and when visiting the page at domain.com/post it would redirect to the version with a slash on the end.
Took me ages to work it out!
Edit:
Actually, just took a more detailed look at your code and noticed there is no routing in there, so this is probably not the cause in your case.
Might be useful for people like me who were looking for a different solution though.
For all the people using rails and angularjs:
The rails framework that maps URLS to views and loads them clashes with the angularjs $route even when you have a single-view application.
To prevent the double-loading of your controller:
go to application.js and remove "//= require turbolinks
You're welcome.

AngularUI integration - accessing module value from script

I have successfully integrated AngularUI into AngularJS application following instructions on stackoverflow (How to integrate AngularUI to AngularJS?).
Now I am trying 'jQuery Passthrough' example from official AngularUI page.(http://angular-ui.github.io/).
<a title="Easiest. Binding. Ever!" ui-jq="tooltip">Hover over me for static Tooltip</a>
<a data-original-title="{{tooltip}}" ui-jq="tooltip">Fill the input for a dynamic Tooltip:</a>
<input type="text" ng-model="tooltip" placeholder="Tooltip Content">
<script>
myModule.value('ui.config', {
// The ui-jq directive namespace
jq: {
// The Tooltip namespace
tooltip: {
// Tooltip options. This object will be used as the defaults
placement: 'right'
}
}
});
</script>
The problem I am having is that 'myModule' variable (or whatever I try here) is not defined.
Without the script, the page is working (at least the static tooltip), so I guess AngularUI is correctly configured.
What should I do to access module variable?
Must this script be included into the controller class?
Thank you.
You're jumping ahead before you cover some basics. In order to code your application you need to declare a module.
Normally this is done by doing something like:
var myModule = angular.module('myApp', ['ui']);
and then myApp becomes the contents of the ng-app attribute.
Alternatively, you can do:
angular.module('myApp').value('ui.config', { ...
if you do not wish to store a reference to the module in a variable. Keep in mind that storing the reference to a variable is the same as if you were to chain these calls on top of one another:
angular.module('myApp', ['ui']).value('ui.config', { ...
Any of these solutions should work for you

Resources