I'm working with Highcharts-ng https://github.com/pablojim/highcharts-ng
Looking through the source code, I see there are some things going on in the directive with scope.$on that I can use to broadcast. For example...
scope.$on('highchartsng.reflow', function () {
chart.reflow();
});
Then in my controller, I can call a watch function on a scope:
$scope.$watch("someElement", function(nV,oV){
if(nV===oV) return;
$scope.$broadcast('highchartsng.reflow');
});
This works fine and makes a lot of sense. What I don't understand is why I can't add additional things to the directive. For example, if I can call .reflow() from the directive, I should be able to call .zoomOut() just as easily, correct?
// This doesn't work when I add it to the directive..
scope.$on('zoomOut', function() {
chart.zoomOut();
});
// And broadcast the change from a scope in the controller
$scope.$watch('someElement', function(nV,oV){
if(nV===oV) return;
$scope.$broadcast('zoomOut');
});
What can be done to make this work? And if it can't be done, how can I make jQuery control it instead? (Is it even possible to make jQuery take over certain aspects of the directive instead of relying on angular for everything?)
That should work. As the comment above says make sure you are calling it on the right scope.
You could just use jquery to get a handle to the chart and then call whatever methods you want. See: How can i get access to a Highcharts chart through a DOM-Container
I'm slow to add many of these types of events as they will apply to all charts on the page and don't seem a very angular way of doing things.
Related
There is a widget in the POS(point of sale) called PaymentScreenWidget and inside that there's a customer_changed method which is called when the customer is changed.
Suppose that I want to call a method after this method is called then how can I do this without interfering with this code?
Interfering with this code leaves a lot of trouble in many case so are there any ways to achieve this?
I want to append some text to it but since there are many module who try to change those code or override it I want to avoid doing it and try to call my method after that method has been called.
You'll have to do some code instrumentation.
For example,
let old_customer_changed = customer_changed;
customer_changed = function(){
// my awesome code
old_customer_changed();
}
You'll have to implement similar thing in whatever modules you are using.
I have a controller where I need to load content using ajax. While it's loading, I'd like a spinner to appear in the interim. The code looks something like the below:
<i class="fa fa-2x fa-spin fa-spinner" ng-show="isLoadingContent"></i>
And the corresponding js:
$scope.isLoadingContent = true;
$q.all(promises).then(function (values) {
$scope.isLoadingContent = false;
// more code - display returned data
However, the UI the spinner does not appear where/when I expect it to appear when I step through the code.
$scope.isLoadingContent = true;
debugger; // the spinner does not appear on the UI
$q.all(promises).then(function (values) {
debugger; // the spinner finally does appear in the UI at this point
$scope.isLoadingContent = false;
// more code - display returned data
I have tried stepping through the code but came up short as to what's going on --
and I am sure I am misunderstanding the sequence of events happening in the Event Loop and where the angular-cycle plays it's role in all of this.
Is someone able to provide an explanation as to why the spinner is set to appear within the promise's method rather than where I set $scope.isLoadingContent? Is it not actually getting set but rather getting queue'd up in the event-loop's message-queue?
------------ EDIT ------------
I believe I came across an explanation as to what's going on. Thanks in large part to, #jcford and #istrupin.
So a little tidbit missing in the original post, the event firing the promise calls and the spinner update was actually based around a $scope.$on("some-name", function(){...}) event - effectively a click-event that is triggered outside of my current controller's scope. I believe this means the $digest cycle doesn't work as it typically does because of where the event-origination is fired off. So any update in the $on function doesn't call $apply/$digest like it normally does, meaning I have to specifically make that $digest call.
Oddly enough, I realize now that within the $q.all(), it must call $apply since, when debugging, I saw the DOM changes that I had expected. Fwiw.
tl;dr - call $digest.
A combination of both answers will do the trick here. Use
$scope.$evalAsync()
This will combine scope apply with timeout in a nice way. The code within the $evalAsync will either be included in the current digest OR wait until the current digest is over and start a new digest with your changes.
i.e.
$q.all(promises).then(function (values) {
$scope.$evalAsync($scope.isLoadingContent = false);
});
Try adding $scope.$apply() after assigning $scope.isLoadingContent = true to force the digest. There might be something in the rest of your code keeping it from applying immediately.
As pointed out in a number of comments, this is absolutely a hack and is not the best way to go about solving the issue. That said, if this does work, you at least know that your binding is set up correctly, which will allow you to debug further. Since you mentioned it did, the next step would then be to see what's screwing up the normal digest cycle -- for example triggering outside of angular, as suggested by user JC Ford.
I usually use isContentLoaded (as oposite to isLoading). I leave it undefined at first so ng-show="!isContentLoaded" is guaranteed to show up at first template iteration.
When all is loaded i set isContentLoaded to true.
To debug your template you need to use $timeout
$timeout(function () { debugger; })
That will stop the code execution right after first digest cycle with all the $scope variable values reflected in the DOM.
I am using AngularJS and angular-datatable library.
I need to invoke modal on click on row.
Here is my part of code:
function rowCallback(nRow, aData, iDisplayIndex, iDisplayIndexFull) {
// Unbind first in order to avoid any duplicate handler (see https://github.com/l-lin/angular-datatables/issues/87)
$('td', nRow).unbind('click');
$('td', nRow).bind('click', function() {
console.log(aData.title);
$timeout(function(){
Modal.showModal({
template : 'views/Modal.html',
Data : aData
});
}, 0);
});
return nRow;
}
console.log function works fine any way, but invoking modal function works as expected only when it wrapped in timeout. So can someone explain why this happening? Why only first function works good? I will be grateful for any explanations.
The reason you need the $timeout, is because you're using a jQuery event with an angular function. This is a bad idea in general and is against the design principles of angular - use ng-click instead.
If you must mix jQuery and angular together, then make sure you do it properly by making angular aware of jQuery events so that it can trigger its digest cycle.
You can trigger a digest in a few ways but the easiest (and most obvious as to what you code is doing) is by using $scope.$apply:
$scope.$apply(function () {
Modal.showModal({
template : 'views/Modal.html',
Data : aData
});
});
The reason the $timeout works is because $timeout is an angular wrapper function that triggers a digest cycle as part of its implementation (it's actually very similar to $scope.$apply, but it's less obvious what it's doing / why it's needed when you review your code later, so I'd advise using $scope.$apply instead).
Further reading: ng-book.
There is no callback for when the browser rendering engine will complete rendering the page.
But rendering the page is handled by the event queue. By using the $timeout function you are assigning Modal.showModal to the end of the event queue - after page rendering methods which have already been queued.
Therefore Modal.showModal will be called after the page has been rendered and work correctly.
I'm working with a 3rd party product where I am extending the UI with my own custom functionality. Within part of that I need to call an event after the UI has been updated with an AJAX call. Luckily the app fires a call to a Custom Event using the Prototype JS library after the call is complete, like this:
$(document.body).fire("ns:customevent");
If I add my own custom event with the same name then this works as expected
$(document).observe("ns:customevent", function(event) {
//do custom stuff here
});
[I could not get $(document.body).observe() to work here but I don't think that really matters.]
My concern here is that there may be other parts of the app that have registered functions against that event, and I am (blindly) overwriting them with my own, which will lead to issues further down the line.
Does Prototype append custom functions even though they have the same name or does it in fact overwrite them? If it does overwrite them then how can I append my function to anything that is already existing? Is there anyway of viewing what
I would imagine something like this, but I hardly know Protoype and my JS is very rusty these days.
var ExistingCustomEvent = $(document.body).Events["ns:customevent"];
$(document).observe("ns:customevent", function(event) {
ExistingCustomEvent();
//do custom stuff here
});
I can't add my event handler or add in code to call my own function, I want to try avoiding the 3rd party library (if that would even be possible).
Thanks.
As an FYI for anyone else that stumbles upon this question, following the comment from Pointy it turns out that Prototype does append the functions to the custom event.
I verified this by trying the following and both alerts fired.
$(document).observe("ns:customevent", function(event) {
alert("ALERT 1");
});
$(document).observe("ns:customevent", function(event) {
alert("ALERT 2");
});
Great :)
I'm working on a project in JavaScript where we're building a Greasemonkey plugin to an organizational site we're using in our office. We're having trouble getting our changes to stay rendered, since we can't simply inject our changes into the existing render function.
As a result, we need to find every event where rendering happens and inject our own render function there. However, there are some events that we can see happening, but we can't hook into them. What I'd like to know is how to bind a function to an object's data member, so that the function is called whenever that member changes. One of our team members seemed to think it was possible, but the method he told us to use didn't seem to work.
What we tried was something along the lines of
window.Controller.bind("change:idBoardCurrent", OMGITWORKED);
where idBoardCurrent is a member of window.Controller and OMGITWORKED is the function we'd like to be called when window.Controller.idBoardCurrent is changed.
I'm not very familiar with JavaScript or data binding, so I have no idea if this is right or wrong, or what is correct or incorrect about it. If someone could point out what to change in this snippet, or if they could suggest another way to go about this, I would be very appreciative.
You can use Object.defineProperty to define a setter and getter for the Objects property
Object.defineProperty(window.Controller,"idBoardCurrent",{
get : function() { return this.val; },
set : function(value) {this.val = value;OMGITWORKED(value); }
});
function OMGITWORKED(param) {
console.log("idBoardCurrent has been Changed to " + param);
}
window.Controller.idBoardCurrent = "Test";
window.Controller.idBoardCurrent = "Test2";
console.log(window.Controller.idBoardCurrent)
Edit: changed the code according to the contexts object
JSBin
As this is specifically Firefox, you can use the mutation events it provides. But note the caveats on them from that page:
The W3C specification for them was never widely implemented and is now deprecated
Using DOM mutation events "significantly degrades" the performance of DOM modifications
If you're able to restrict yourselves to Firefox 14 and higher, you can use the new mutation observers stuff instead.
This is, when I am not totally wrong, more a question of javascript.
I found some information about that topic
Listening for variable changes in JavaScript or jQuery
jQuery trigger on variable change
Javascript Track Variable Change
Sorry when I didn't understand the topic.
All the best