AngularUI integration - accessing module value from script - angularjs

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

Related

AngularJS with Salesforce

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!

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: How to compile custom directive added by a service?

Using AngularJS and UI Bootstrap, I want to dynamically add alerts to DOM. But if I dynamically add an <alert> element to DOM, it's not compiled automatically. I tried to use $compile but it doesn't seem to understand tag names not present in core AngularJS. How can I achieve this? Is it even the right way to "manually" add elements to DOM in services?
See Plunker. The alert in #hardcodedalert is compiled and shown correctly but the contents of #dynamicalert are not being compiled.
Edit:
I'd later want to have alerts shown on different context and locations on my web page and that's why I created a constructor function for the alerts, to have a new instance in every controller which needs alerts. And just for curiosity's sake, I was wondering if it's possible to add the <alert> tags dynamically instead of including them in html.
I've updated your plunker to do what you're trying to do the "angular way".
There are a few problems with what you were trying to do. The biggest of which was DOM manipulation from within you controller. I see you were trying to offset that by handling part of it in the service, but you were still referencing the DOM in your controller when you were using JQuery to select that element.
All in all, your directives weren't compiling because you're still developing in a very JQuery-centric fashion. As a rule of thumb you should let directives handle the adding and removing of DOM elements for you. This handles all of the directive compiling and processing for you. If you add things manually the way you were trying, you will have to use the $compile provider to compile them and run them against a scope... it will also be a testing and maintenance nightmare.
Another note: I'm not sure if you meant to have a service that returned an object with a constructor on it, so I made it just an object. Something to note is that services are created and managed in a singleton fashion, so every instance of that $alertService you pass in to any controller will be the same. It's an interesting way to share data, although $rootScope is recommended for that in most cases.
Here is the code:
app.factory('alertservice', [function() {
function Alert() {
this.alerts = [];
this.addAlert = function(alert) {
this.alerts.push(alert);
};
}
return {
Alert: Alert
};
}]);
app.controller('MainCtrl', function($scope, alertservice) {
var myAlert = new alertservice.Alert();
$scope.alerts = myAlert.alerts;
$scope.add = function() {
myAlert.addAlert({"text": "bar"});
};
});
Here are the important parts of the updated markup:
<body ng-controller="MainCtrl">
<div id="dynamicalert">
<alert ng-repeat="alert in alerts">{{alert.text}}</alert>
</div>
<button ng-click="add()">Add more alerts...</button>
</body>
EDIT: updated to reflect your request

Resources