In this link: http://css-tricks.com/snippets/jquery/jquery-plugin-template/ it has a line of code that says
// Add a reverse reference to the DOM object
base.$el.data("yourPluginName", base);
what does the "reverse reference to the DOM object" mean?
Assuming that you know the jQuery data function:
It's storing a reference to the instance of the class in the data cache of jQuery, meaning that the stored instance can be used to access the initial base object if it in the current context is not available.
This way, the class instance can be used later. However, the use of the prototype keyword upon the initial class that the instance were created from will modify the instance.
EDIT:
Ooops, it seems that Anurag is right, and I was giving wrong information.
Sorry, the information I gave in initial answer was not completely correct. I've updated the answer, so it now tells the truth.
In the comments you're asking:
so you mean its storing the current state of "base" in the data cache but if we make changes to "base" later on then the one in the data wont be affected? so if for some reason we needed to get the original one again we can do data('yourPluginName') to retrieve it? can you give me an example of when this would be helpful?
It seems that none of the statements are correct.
As I did obviously not remember adequately, the thing stored in data is only a reference to the object:
var obj = {};
obj.hello = "Hello";
$("#someElement").data("object", obj);
obj.world = " world.";
alert(
obj.hello +
$("#someElement").data("object").world
); // alerts "Hello world."
BTW, JavaScript variables with names like this base-thing (but, more often seen as that or similar) are typically used to represent the current context, accessed through the this keyword, which on many occasions is more easy to store in another variable due to scoping/context changes, that will make the current context and therefore this, change.
Also due to issues with context, the stored value in data could be used to access the specific object instance from another context (that is, when this represents something else), instead of the version of the base object that was continually used after a copy of it was stored.
I hope this answered you questions :D
The technique and the problem it solves is general and not specific to jQuery plugins. There may be cases where a Javascript object corresponds to a DOM element, and wraps logic specific to that DOM element. This object might be interested in listening to events such as clicks that happen within that DOM element. The information we get in those callbacks is the element that triggered it, and not the associated object. You could use jQuery's data API or any type of map in general to retrieve the corresponding object, and do something with it.
Related
Attempting to assign a scope object to a JavaScript variable to do minor manipulation before sending to my API. However, any changes made to the JavaScript variable change the scope object.
var recruitingCallListOutput = $scope.RecrutingCallingList.Recruit;
// manipulation of recruitingCallListOutput
The manipulation actually still updates the scope object which is not desired. Feel I am not understanding something in AngularJS correctly. Is there a way to grab the data and detach it from the scope?
In your example, recruitingCallListOutput is a reference to $scope.RecrutingCallingList.Recruit (see https://codeburst.io/explaining-value-vs-reference-in-javascript-647a975e12a0 for more detail.) You will want to make a copy of $scope.RecrutingCallingList.Recruit.
If Recruit is a shallow object, meaning no nested objects (property values are primitives only), you can simply do
var recruitingCallListOutput = Object.assign({}, $scope.RecrutingCallingList.Recruit);
If you have nested objects/arrays as property values, you'll need to deep copy. It's been a while since I have been in the angular world, but
var recruitingCallListOutput = angular.copy($scope.RecrutingCallingList.Recruit)
you could actually use angular.copy in both examples.
This is nothing to do with AngularJS. It's Javascript, and it's expected behaviour.
For example, if you open the browser console (F12->Console) right now and run this:
var foo = {x:1};
var copy=foo;
copy.x=2;
console.log(foo.x);
you will see {x:2} printed out.
This is the same behaviour you would expected for any object reference in Javascript, C#, Java, etc. Because you are making a reference and not a copy, any changes to the reference are actually changes to the original.
The simplest way to solve this problem in your case is to copy the values you are interested in from the item in question into a totally separate object and modify that copy.
e.g.
var recruitingCallListOutput = {
name: $scope.RecrutingCallingList.Recruit.name,
age:$scope.RecrutingCallingList.Recruit.age,
modifiedSomething: $scope.RecrutingCallingList.Recruit.something + 42 //or whatever modifications you need to make
...and so on.
};
There are ways to "clone" an object in Javascript but unless your object is really really complex I would be careful. And consider if you really need all of the properties of the original object anyway, perhaps you only need to send some of them to your backend.
I want to make an UI object that saves references to DOM objects and also some UI strings, so I can use it all over my code and can handle name changes easily. Kind of like this:
var UI = {
DOMelem0: document.getElementById('imUnique'),
DOMelem1: document.getElementById('imSpecial')
};
However, I think that everytime I would access DOMelem0 (by calling UI.DOMelem0), for instance, I'd be calling the getElementById() function, is that what happens?
Or is it no different than storing the elem in a scoped variable? (Like so: var elem = document.getElementById('cow');)
I'm worried about any performance issues this might cause if I were to have lots of UI elements, although I guess they'd be minimal. Either way, I wouldn't want to be calling the DOM method all the time.
Thanks.
Calling UI.DOMelem0; will not call document.getElementById('imUnique').
document.getElementById('imUnique') is only called when you first create the UI object.
I maintain a custom library consisting of many dijit widgets at the company I work at.
Many of the defects/bugs I have had to deal with were the result of this.inherited(arguments) calls missing from overriden methods such as destroy startup and postCreate.
Some of these go unnoticed easily and are not always discovered until much later.
I suspect I can use dojo\aspect.after to hook onto the 'base' implementation, but I am not sure how to acquire a handle to the _widgetBase method itself.
Merely using .after on the method of my own widget would be pointless, since that wouldn't check whether this.inherited(..) was inded called.
How can I write a generic test function that can be passed any dijit/_WidgetBase instance and checks whether the _widgetBase's methods mentioned above are called from the widget when the same method is called on the subclassing widget itself?
Bottom-line is how do I acquire a reference to the base-implementation of the functions mentioned above?
After reading through dojo's documentation, declare.js code, debugging, googling, debugging and hacking I end up with this piece of code to acquire a handle to a base method of the last inherited class/mix-in, but I am not entirely happy with the hackiness involved in calling getInherited:
Edit 2 I substituted the second param of getInherited with an empty array. While I actually get a reference to the method of the baseclass using aspect doesn't work. It appears this approach is a bust.
require(['dijit/registry','dojo/_base/declare','mycompany/widgets/widgetToTest'],
function(registry,declare,widgetToTest)
{
var widget = registry.byId('widgetToTestId');
var baseStartup = getBaseMethod(widget,'startup');
function getBaseMethod(widget,methodName){
return widget.getInherited(methodName,[]);
}
//This is the method body I want to use .after on to see if it was called, it returns the last overriden class in the array of inherited classes. (a mixin in this case, good enough for me!)
alert(baseStartup);
});
I have given up trying to use dojo/aspect.
I have instead opted to modify the code of our custom base widget to incorporate snippets such as the one below. They are automatically removed when creating a release-build in which console-calls and their content are removed:
console.log(
function(){
(this._debugInfo = this._debugInfo|| {}).postCreate=true;
}.call(this)
);
A simple method in boilerplate code I added near the unittests is available so that I can call it on all mycompany.widgets.basewidget instances in their respective unittests.
I need short messages disappearing after preset time. Please see the fiddle here: http://jsfiddle.net/X88F9/1/.
It works well, what I am not sure about is the reference for each created object:
function addObject() {
new SomeObj(Math.random() * 1000 + 300);
}
it is not stored in any variable, can I just leave it as it is ? Or do I need to push them in some array ?
I also found this recommendation to put all in closures: https://stackoverflow.com/a/10246262/2969375, but not sure if necessary in my case and if yes, then how.
My answer to the question is: Javascript does not need a reference to the object to work, as proofed by your fiddle. So the question is more about if you need a reference to the object, to do other stuff with it later on. If you, for instance, would like to give the user the ability to click the temporarily display message and stop it from disappearing, than you can put all that code in a closure and do not need a reference, too. But if you would like to display the very same object again after it was removed from the DOM, than you need to store it in an array, other object, or variable, depending on your needs and ways to find it in a list.
I know understand more about how jQuery stores data.
Is there any advantage to doing one or the other of these:
$('#editCity').data('href', "xx");
var a = $('#editCity').data('href');
or
$('#editCity').attr('data-href', "xx");
var a = $('#editCity').attr('data-href');
One more related question.
If I have this:
var modal = { x: 'xx', y: 'yy' };
Can I also store this using .data( .. ) ?
Storing property values directly on DOM elements is risky because of possible memory leaks. If you're using jQuery anyway, the .data() mechanism is a wonderful and safe way to keep track of per-element information. It allows for storage of arbitrary JavaScript data structures too, not just strings.
edit — when your HTML markup contains data-foo attributes, those are implicitly read when the keys are accessed. That is, if your HTML looks like this:
<div id="div1" data-purpose="container">
Then in jQuery:
alert( $('#div1').data('purpose') ); // alerts "container"
Furthermore, jQuery will also do some "smart" analysis of the attribute values. If a value looks like a number, jQuery will return a number, not a string. If it looks like JSON, it de-serializes the JSON for you.
edit — here's a good trick: in the Chrome developer console (the "Console" view), you can type JavaScript expressions and have them evaluated. The evaluation is always done in the context of the page you're working on. If you select an element from the "Elements" view, then in the console the JavaScript symbol $0 will refer to that selected DOM element. Thus you can always inspect the "data" map for an element by going to the console and typing something like:
$($0).data("something");
The .data() function, if called with no parameters, returns all the key/value pairs:
$($0).data();
The most interesting point about the data function is that you can add any kind of object, for example your modal. And jQuery, as stated in the documentation, take care of avoiding memory leaks when the DOM changes :
The jQuery.data() method allows us to attach data of any type to DOM
elements in a way that is safe from circular references and therefore
free from memory leaks.
For strings, memory leaks aren't possible but the main difference is that the first solution is cleaner (more coherent if you might store other data than strings in other parts of your application), clearer (the intent is evident), and doesn't force CSS calculation (DOM isn't changed).
They both have advantages... That said, 99% of the time you should be using .data('whatever', value)
Advantages of using .data('whatever', value):
less apt to cause memory leaks because it's not using the DOM.
Slightly faster to pull data from memory than from the DOM.
Can put any type of object in it without serializing it to JSON first.
Advantages of using .attr('data-whatever', value):
compatible with .data('whatever')
allows you to select the element by the value: $('[data-whatever=foo]')
You can put any object in it, but it will need to serialize if it's a complex type.