Javascript nested dictionary null values - javascript

Below I have declared a 'class' in JS and am writing methods for it. The class represents a widget (more info class structure).
The problem I'm having is that when I print 'this' inside the setAttr ibutes method, the output is:
And when I print 'this.opts' in the very next line:
NOTE: The values of 'status' and 'power' are shown as 'null' in the second output before expanding it. This can be the only possible reason behind getting 'null' while trying to print 'this.opts.status'.
CODE
function PowerStatus(options) {
this.opts = {
meterName: '-',
displayName: null,
status: null,
power: null,
mainDiv: null,
};
this.opts = $.extend(this.opts, options);
this.opts.mainDiv = '#' + this.opts.mainDiv;
this.onClick = function () {
console.log('Clicked ' + this.opts.meterName);
};
// fill in missing attributes
this.getAttributes();
this.setHtml();
this.bindUIActions();
}
PowerStatus.prototype.getAttributes = function () {
var _this = this;
if (this.opts.displayName == null) {
getDisplayName(function (dName) {
_this.opts.displayName = dName;
}, _this.opts.meterName);
}
if (_this.opts.status == null || _this.opts.power == null) {
_this.getStatus(function (status, power) {
_this.opts.status = status;
_this.opts.power = power;
}, _this.opts.meterName)
}
};
PowerStatus.prototype.setHtml = function () {
var _this = this;
var divType = this.opts.mainDiv.split('-').slice(1).slice(0, -1).join('_');
var url = '/static/' + divType + '/html/' + divType + '.html';
$(this.opts.mainDiv).load(url, function () {
_this.setAttributes();
});
};
PowerStatus.prototype.setAttributes = function () {
var div = $(this.opts.mainDiv).find('.load-name');
var span = $('span:first', div);
span.text(this.opts.displayName);
div = $(this.opts.mainDiv).find('.load-value');
span = $('span:first', div);
span.text(this.opts.power);
};
PowerStatus.prototype.bindUIActions = function () {
var _this = this;
$(this.opts.mainDiv).on('click', function () {
_this.onClick();
});
};
PowerStatus.prototype.getStatus = function (callback) {
$.ajax({
method: "GET",
dataType: "json",
url: "/widget/power_status/status/",
data: {name: this.opts.meterName},
success: function (data) {
if (typeof callback === "function") callback(data.status, data.power);
},
error: function (jqXHR, textStatus, errorThrown) {
console.log(textStatus, errorThrown);
}
});
};

The value of this inside your click handler is not the same as the value outside that handler. You need to stash this in a local variable and use that instead.
var statusObj = this;
this.onClick = function () {
console.log('Clicked ' + statusObj.opts.meterName);
};
Alternatively, you could use .bind():
this.onClick = function () {
console.log('Clicked ' + this.opts.meterName);
}.bind(this);
The value of this is always set on every individual call to a function based on the circumstances of the call.

Related

How to disable method call if instance of object doesn't exist (javascript)

Is there a way to not call a method from the function object (instance of it) if that instance doesn't exist?
This is my function for sticky sidebar and it has 2 methods;
init() and updateSticky();
function stickySideBar(element, options = {}) {
var _this = this;
_this.init = function () {}
_this.updateSticky = function (timeout) {
//this is actually just a debouncer that calls init method
}
}
I want to use this updateSticky on window resize
$(window).on("resize", function () {
newsletterBlog.updateSticky();
sideBarBlog.updateSticky();
if ($(productsSticky.element).length > 0) {
productsSticky.updateSticky();
}
});
now I use if loop to check if an element exists but I would like to do that inside of the instance of that function
if i dont have if loop i get "Uncaught TypeError: e.updateSticky is not a function".
cheers
EDIT
here is the function
function stickySideBar(element, options = {}) {
var _this = this;
console.log("_this :>> ", _this);
//declared element
_this.debouncer;
_this.element = element;
if ($(_this.element).length === 0) {
return;
}
// declared options
_this.parentElementClass = options.parentElementClass;
_this.wrapClass = options.wrapClass;
_this.activeStickyClass = options.activeStickyClass;
_this.top = options.top;
_this.width = options.width;
_this.activeBottomClass = options.activeBottomClass;
_this.disableOnMobile = options.disableOnMobile ? options.disableOnMobile : true;
_this.breakpoint = 992;
_this.init = function () {
};
_this.updateSticky = function (timeout) {
if ($(_this.element).length === 0) return;
var timeoutVal = timeout ? timeout : 100;
clearTimeout(_this.debouncer);
_this.debouncer = setTimeout(function () {
_this.init();
}, timeoutVal);
};
return _this.init();
}

How to call variable from within a function

I can't seem to be able to call a variable set earlier by a script in order to control an element.
Script to load map onto page
<script>
window.scribblemaps = {
settings: {
baseAPI: "google",
key: 'key'
}
};
var loadmap = function () {
var sm = new
scribblemaps.ScribbleMap(document.getElementById('ScribbleMap'),
{ controlMode: { 'mapType': scribblemaps.ControlModes.SMALL } }
);
}
</script>
html which creates a div to display map
<div class="SM" id="ScribbleMap"></div>
javascript to save the map
(function($) {
$(document).ready(function() {
$('#start_design').click(function(){
var id = $(this).attr('href');
var offset = $(id).offset().top - 70;
$('body, html').animate({scrollTop: offset}, 1000);
})
$('#save_design_maps').on('click',function(){
var project_name = $('#project_name');
if( project_name.val() !== '') {
project_name.css('border-color', '');
var sm = document.getElementById('ScribbleMap');
var uid = (new Date().getTime()).toString(36);
var title = project_name.val();
var details = {
"id": uid,
"password": "aaa",
"title": title,
"description": title,
"secure": false,
"listed": false,
"projectId": "ID",
"groupCode": "<groupCode>"
};
// console.log(sm);
// console.log(JSON.stringify(sm.data.getSmJSON(), null, 2));
sm.map.save(details, function (completeEvent) { }, function (errorEvent) { });
sm.map.addListener(scribblemaps.MapEvent.MAP_SAVED, function (event) {
alert('Map is saved!');
var sm_share_link = 'https://www.scribblemaps.com/maps/view/' + title.replace(/\s+/g, '_') + '/' + uid;
$('#map_url').val(sm_share_link);
console.log(sm_share_link);
});
sm.map.addListener(scribblemaps.MapEvent.MAP_SAVE_ERROR, function (event) {
alert('Map can not be saved!');
});
} else {
alert('Please fill the Project Name Field');
project_name.css('border-color', 'red');
}
});
});
$(window).scroll(function() {
});
$(window).resize(function() {
});
$(window).load(function() {
});
})(jQuery);
Expected result is for the javascript to call a function on the Scribblemap api to Save the map.
Actual result is Uncaught TypeError: Cannot read property 'map' of undefined
Since html elements don't have the map attribute I believe that you are trying to access this sm:
var loadmap = function () {
var sm = new
scribblemaps.ScribbleMap(document.getElementById('ScribbleMap'),
{ controlMode: { 'mapType': scribblemaps.ControlModes.SMALL } }
);
}
You have to pass this sm instance to your function in order for it to work.

javascript fire method before or after another method is called

I would like to know what are the common approach to make this concept works:
function Abc () {
var beforeMethod = function (e) {
console.log(e);
};
this.before('bob ana', beforeMethod);
}
Abc.prototype.ana = function () { console.log('ana'); }
Abc.prototype.bob = function () { console.log('bob'); }
Abc.prototype.maria = function () { console.log('maria'); }
//
var abc = new Abc();
abc.ana();
It's supposed to call beforeMethod before bob or ana is called.
Quickly :
need to be tested and securised, but i think it do the trick !
I haven't understood what your e mean so i put the called method name in it !
var el = document.getElementById('debug');
var $l = function(val) {
console.log(val);
el.innerHTML = el.innerHTML + '<div>' + val + '</div>';
};
//___________________________________________________________________
var Before = function( methods , func , context){
methods.split(' ').map(function(m){
var ori = context[m];
if(ori){
context[m] = function(){
func.call(context , m);
return ori.apply(context , arguments);
};
}
});
};
var Abc = function () {
var beforeMethod = function (e) {
$l('from beforeMethod : ' + e);
};
Before('bob ana ', beforeMethod , this);
};
Abc.prototype.ana = function () { $l('from ana '); };
Abc.prototype.bob = function () { $l('from bob '); };
Abc.prototype.maria = function () { $l('from maria '); };
var abc = new Abc();
abc.ana();
abc.maria();
abc.bob();
<div id='debug'>Debug
<div>
I think the way to do this is to save the old prototype function in a property.
function Abc() {
this.oldana = this.prototype.ana;
this.oldbob = this.prototype.bob;
this.prototype.ana = function(e) {
console.log(e);
this.oldana();
}
this.prototype.bob = function(e) {
console.log(e);
this.oldbob();
}
}

call custom event dynamically on jquery plugin

I have a plugin with the following structure:
(function($){
function pluginName(el, options) {
var _this = this;
_this.defaults = {
someOptions: '',
onSlideStart: function() {},
onSlideEnd: function() {},
};
_this.opts = $.extend({}, _this.defaults, options);
$(el).on("slideStart", function() {
_this.opts.onSlideStart.call();
});
$(el).on("slideEnd", function() {
_this.opts.onSlideEnd.call();
});
}
pluginName.prototype = {
someFunctions: function() {
}
};
$.fn.pluginName = function(options) {
if(this.length) {
this.each(function() {
var rev = new pluginName(this, options);
rev.init();
$(this).data('pluginName', rev);
});
}
};
})(jQuery);
If I call it the following way, everything is okay:
$('.element').pluginName({
someOptions: 'full',
onSlideStart: function() {
console.log('slideStart!');
},
onSlideEnd: function() {
console.log('slideEnd!');
},
});
But I want to dynamic load the custom event handler like this:
(function($){
function pluginName(el, options) {
var _this = this;
_this.defaults = {
someOptions: '',
onSlideStart: function() {},
onSlideEnd: function() {},
};
_this.opts = $.extend({}, _this.defaults, options);
for (var optionName in _this.opts) {
var
optionValue = _this.opts[optionName],
optionType = typeof(optionValue)
;
if(optionType == 'function') {
optionNames = optionName.split('on');
eventName = global.lowerFirstLetter(optionNames[1]);
$(el).on(eventName, function() {
eval('_this.opts.' + optionName + '.call();');
});
}
}
}
...
})(jQuery);
But this does not work. When I call the plugin with the "dynamic" part, it always call the slideEnd-function. So am I doing it wrong or is it just impossible with my plugin-pattern to call the custom event-handler dynamically?
Why use eval ? It's usually bad to use eval.
if(optionType == 'function') {
optionNames = optionName.split('on');
eventName = global.lowerFirstLetter(optionNames[1]);
$(el).on(eventName, _this.opts[optionName]);
}
Try it and let me know.

Triggering the return key on event unexpectedly refreshes page and gives undefined error - JavaScript

When I click in field, type text, and press return on keyboard it triggers the initializeTable function that refreshes page and gives error form[0] undefined. However, when I use change event to change dropdown selection, it doesn't cause this unexpected behavior. So I'm not sure why pressing return key in text field is causing all this. Thanks for response.
<script>
(function($){
var listview = $('#listview');
var lists = (function(){
var criteria = {
dropFilter: {
insert: function(value){
if(value)
return {"filter" : value};
},
msg: "Filtering..."
},
searchFilter: {
insert: function(value){
if(value)
return {"search" : value}
},
msg: "Searching..."
}
}
return {
create: function(component){
var component = component.href.substring(component.href.lastIndexOf('#') + 1); //sites
return component;
},
setDefaults: function(component){
var parameter = {};
switch(component){
case "sites":
parameter = {
'url': 'sites',
'order': 'site_num',
'per_page': '20'
}
}
return parameter;
},
getCriteria: function(criterion){
return criteria[criterion];
},
addCriteria: function(criterion, method){
criteria[criterion] = method;
}
}
})();
var Form = function(form){
var fields = [];
$(form[0].elements).each(function(){
var field = $(this);
if(typeof field.attr('alter-data') !== 'undefined') fields.push(new Field(field));
})
}
Form.prototype = {
initiate: function(){
for(field in this.fields){
this.fields[field].calculate();
}
},
isCalculable: function(){
for(field in this.fields){
if(!this.fields[field].alterData){
return false;
}
}
return true;
}
}
var Field = function(field){
this.field = field;
this.alterData = true;
this.component = {'url' : window.location.hash.substring(window.location.hash.indexOf('#') + 1)};
this.attach("change");
this.attach("keypress");
}
Field.prototype = {
attach: function(event){
var obj = this; //our Field object
if(event == "change"){
obj.field.bind("change", function(){
return obj.calculate();
})
}
if(event == "keypress"){
obj.field.bind("keypress", function(e){
var code = (e.keyCode ? e.keyCode : e.which);
if(code == 13){
return obj.calculate();
}
})
}
},
calculate: function(){
var obj = this,
field = obj.field,
component = obj.component,
msgClass = "msgClass",
msgList = $(document.createElement("ul")).addClass("msgClass"),
types = field.attr("alter-data").split(" "),
container = field.parent(),
messages = [];
field.next(".msgClass").remove();
for(var type in types){
var criterion = lists.getCriteria(types[type]);
if(field.val()){
var result = criterion.insert(field.val());
container.addClass("waitingMsg");
messages.push(criterion.msg);
obj.alterData = true;
initializeTable(component, result);
}
else {
return false;
obj.alterData = false;
}
}
if(messages.length){
for(msg in messages){
msgList.append("<li>" + messages[msg] + "</li");
}
}
else{
msgList.remove();
}
}
}
$('#dashboard a').click(function(){
var currentComponent = lists.create(this);
var defaults = lists.setDefaults(currentComponent);
initializeTable(defaults);
});
var initializeTable = function(defaults, custom){
var custom = custom || {};
var query_string = $.extend(defaults, custom);
var params = [];
$.each(query_string, function(key,value){
params += key + '=' + value + "&";
})
var url = params.substring(params.indexOf("url")+4,9);
params = params.substring(params.indexOf("&")+1).replace(params.substring(params.lastIndexOf("&")),"");
$.ajax({
type: 'GET',
url: '/' + url,
data: params,
dataType: 'html',
error: function(){},
beforeSend: function(){},
complete: function() {},
success: function(response) {
listview.html(response);
var form = $('form');
form.calculation();
}
})
}
$.extend($.fn, {
calculation: function(){
var formReady = new Form($(this));
if(!formReady.isCalculable){
return false;
}
}
})
})(jQuery)
</script>
Rather than going through whole script, the actual issue is with this:
if(event == "keypress"){
obj.field.bind("keypress", function(e){
var code = (e.keyCode ? e.keyCode : e.which);
if(code == 13){
return obj.calculate();
}
})
}
}
Finally, I got it to work this this:
if(event == "keypress"){
obj.field.bind("keypress", function(e){
var code = (e.keyCode ? e.keyCode : e.which);
if(code == 13){
e.preventDefault();
return obj.calculate();
}
})
}
},
Hence, we first prevent default and then execute our custom function.

Categories

Resources