I am writing an app in AngularJS. I need to expose a function that will be called by an outside library.
I need to have my third party library call
executeFunction(param)
and have my angular app respond accordingly.
My first thought was to create a directive that I could apply to a page that would tell the page to listen for this event(function) to be called but I can't seem to wrap my head around how to do this.
If by "outside library" you mean pure javascript/jquery, there are a number of answers to this question. They all propose the same solution, namely that the Controller is exposed via the DOM element id, see the following links:
Call Angular Function with Jquery
AngularJS. How to call controller function from outside of controller component
Creating a factory or service will not help as you have no way to inject/expose an angular service to a jquery function.
Rather than the above solutions, I would suggest trying to write an event handler. You could create an angularjs directive with a link function that registers a jquery custom event listener. The directive would contain a nested controller to handler the required logic. Your jquery/javascript code could then simply trigger the event (passing along any data required)
jQuery customer events:
https://learn.jquery.com/events/introduction-to-custom-events/
I think all of this is however, bad practice. I would recommend that you reconsider the design of what you are trying to accomplish.
you can make an factory or service or even more robust solution will be to make ab complete module
angular.modue("myLib")
.factory("myLibFactory",function(){
return{
executeFunction :function(param){}
}
})
Related
Is it possible to create javascript elements like OpenStreetMap or jQuery inside a vaadin application?
Because vaadin websites are created by programming in java and letting the compiler autocreate the DOM and JavaScript out of it?
So, is it possible at all?
You can create such an integration with AbstractJavaScriptComponent
The basic idea here is to subclass this class, annotate with #JavaScript to pull in the needed JS libs. Then write at least a global function, that sets up your lib in the DOM (you will have a <div> at your disposal). Your component can hold state, the server side can call defined functions on the client (while sending e.g. state) and the client can call server functions (params passed as JSON).
The Wiki has an example how to include such a component
There are some easy and cheap solutions which are not the best in the long term, but they may be enough:
1)
If you just want to render some html you cant insert it as the value of a label and change its Content Mode to html.
https://vaadin.com/book/-/page/components.label.html
2)
If you just want to execute some javascript code after a ui event you can call Javascript.getCurrent().execute(javascriptCode).
https://vaadin.com/book/vaadin7/-/page/advanced.javascript.html
Notice that if you are trying to do some re-usable components, this is not the right answer
I'm turning a piece of a non-angular web page into an Angular version by angular.bootstrapping it with an Angular module. It works great except for the fact that it needs to communicate with the other parts of the page. Unfortunately I cannot convert the rest of the page to Angular at this time.
The best way I've figured to do this so far is by firing vanilla JS events on the bootstrapped element containing the information I need to communicate.
Are there established patterns or better ways of doing this?
If you need to send a message from vanilla javascript to an AngularJS controller, you can access the scope like this:
var ngScope = angular.element('[ng-controller]').scope();
// or choose a more appropriate selector...
Then, you can do whatever you want on the scope such as broadcast an event or even just invoking a function:
ngScope.$broadcast('myEvent');
ngScope.$apply(ngScope.controllerFunction());
Sending a message from Angular to vanilla javascript should be much simpler. Simply invoke a global event or just access a global function/property.
I had the same problem when I started to migrate the project I am working on to Angular. I had to communicate on different type of events like clicks with my non angular app. If you would like to use a known design pattern you can go with "Mediator pattern". It is a publish/subscribe based communication. You can have a singleton global instance of the mediator and access it from both angular and your non-angular app
Here's a link for the lib: http://thejacklawson.com/Mediator.js/
Before your app (both of them) loads you can do something like this:
window.mediator = new Mediator();
Later you can have in your Angular app a service like so:
angular.module()
.service('mediator', function() {
var mediator = window.mediator || new Mediator();
return mediator;
});
And from your non-angular app you can simply do:
mediator.subscribe('something', function(data){ ... });
And from your Angular controller or whatever you have you will inject the mediator service created and use it like so:
mediator.publish('something', { data: 'Some data' });
Now you have both an Angular and non-Angular way of communicating between your apps.
This solution did wonders for me.
$on only listen for angular event such as $braodcast & $emit only and they will work within bootstrapped app module only.
If you want to listen jQuery events then it should use .on/.bind as like we do in jquery like $('selector').on('event',function(){});
If multiple events are associated with single DOM element then prefer Directive would be the better way get track of element event.
Directive:
app.directive('myCustomer', function() {
return {
restrict: 'E',
compile: function(element,attrs){
element.on('click focus blur',function(){
//code here
});
}
};
});
Otherwise you can bind event listener on specific element, then you can bind it by taking help of jQLite using $document, $window, $element(Provides controller level element) dependency.
Controller
$document.find('.myClass').on('click',function(e){ //placing on specific element.
//code here
});
Plunkr Example
Hope this could help you, Thanks.
I am loading an angular 'template' using ajax. This template renders a bootstrap modal form when I call $compile ... this works, everything fine here. But what I need is support of embedding controllers within this lazy loaded 'template' (Preferably I want to handle this client side so on server side everything can just look normal).
The thing is when I use ng-controller inside this template and define a function controller inside a script tag it fails. It tells me it cant find the controller function. I understand why this is happening, the script has not yet been initialized. I am just looking for a solution. How can I make the embedded script tags initialize first? Should I extract them, inject them somewhere and then compile the remainder? Or is there a more elegant way?
Lets have look in AngularJS documentation and show the integration with the browser event loop.
So you can see that AngularJS have its own event loop, which consists of three phases: compile, digest and apply.
When you call compile it will only loads the html markup and insert it. You should call apply also.
With apply you will set the execution scope. This will register an watcher that listens to changes.
New to Angular so I apologize if the question is silly.
So I'm making an app and one part of it is outside of Angular's "scope" so to speak and this part is responsible for receiving incoming messages (xmpp)
And then there is that Angular controller that has to be notified about incoming messages. What I did is an ugly work around but it works:
view.html:
<button ng-click="refreshLayout()" id="refreshLayoutButton" style="display:none"></button>
controllers.js:
.controller('chatCtrl', function($scope) {
$scope.refreshLayout = function() { ... }
})
outside.js:
if(incomingMessage) {
$("#refreshLayoutButton").click();
// append the message to view.html
}
Is there anyway to exclude jQuery? I want to send the message from outside.js to chatCtrl and then send it to view.html
OR
just notify about the event so it could invoke $scope.refreshLayout (techincally I can append incoming messages directly to view.html using jQuery without Angular, but the first option is still more preferable)
You should trigger event when there are incoming messages.
In outside.js use $broadcast when there are incoming messages.
In controller.js wait for that event to happen with $on.
Here's a simple example: http://jsfiddle.net/simpulton/XqDxG/
... technically I can append incoming messages directly to view.html using jQuery without Angular
I strongly recommend to use Angualrjs only. (For me I would remove jQuery and use only in specific cases in Directives). Angular itself includes jQuery-lite edition within it
New to Angular ...
Please follow this How do I “think in AngularJS” if I have a jQuery background? first, it will make things a bit clearer
So I hope outside.js: from your example means some Directive logic that gets event and need notify controller about.
We can listen on event into Directive and Directive can notify controller by using $eval for example. Here is basic example how $eval works: Demo Fiddle
However (for isolate scope) the other way is just to map event method. Please take a look on THIS example where Google maps notifies controller about zoom change event received.
I'm trying to wrap a native JavaScript functionality around an angularjs module and I need to bootstrap some code on DOMloaded event handler.
document.addEventListener("DOMContentLoaded",function(){
//bootstrapper code
})
I'm a little confused if this is needed in the angular domain or not or maybe I might just be repeating something that has already been called by angular which I could have simply attached my code to. If I put the bootstrapper code in the module's run block, will it achieve the same effect, the docs says
It is executed after all of the service have been configured and the injector has been created.
with respect to the DOMLoaded Event, has it already been fired at this time?
Anyone know anything about this?
angular.module('myApp', []).run(function($rootScope) { }); is similar to $(document).load(function() {}); in jQuery but if a part of the page is being rendered using XHR then run() method will not be helpful.
You either have to write your logic inside below event
angular.module('myApp', []).run(function($rootScope) {
$rootScope.$on('$viewContentLoaded', function() {
// here
});
});
Or you better off writing a custom directive depending upon what you have to achieve.