2

Hello guys i know my question is similar to other questions but my problem is different. Please listen to me carefully.

Simply i just want to know if am calling a function again and again how to set a condition in my plugin code that if am not calling that particular section is not run.

I have write a plugin type short code in jQuery. which is specific for my project. It works for set width and height of that particular element which i'll pass in parameters. On window load and window resize. Am a beginner in jquery so am not too much familiar with objects.

here is the code

//creating some universal variable
var _W, _H, _header, _lH, _lW, _lH1, _lH2, _lH3;

(function($){
    adjust = function(options) {

    var defaults = { 
        headerClass: '',
        containerClass : '',
        Hlevel1:{space:0, divClass :'', prevDivClass : ''},
        Hlevel2:{space:0, divClass :'', prevDivClass : ''},
        Hlevel3:'',
        Wlevel1 : {space:0, divClass : '', prevDivClass : ''},
        Wlevel2 : {space:0, divClass : '', prevDivClass : ''}

    };
    var opts = $.extend(defaults, options);

    function performAdjust(){
            _W = $(window).width(); //retrieve current window width
            _H = $(window).height(); //retrieve current window height
            _headH = $(opts.headerClass).outerHeight(true);//retrieve current header height


            // take left height after header height subtract to window height
            _lH = _H - _headH

            //make a variable for level one height
            _lH1 = _lH - (opts.Hlevel1.space + $(opts.Hlevel1.prevDivClass).outerHeight(true))

            //make a variable for level two height
            _lH2 = _lH1 - (opts.Hlevel2.space + $(opts.Hlevel2.prevDivClass).outerHeight(true));



            //applying height on main container
            $(opts.containerClass).css({height:_lH});


            //applying height on level 1 div
            $(opts.Hlevel1.divClass).css({height:_lH1 });


            //applying height on level 2 div
            $(opts.Hlevel2.divClass).css({height:_lH2 });


            //take left width after level one element

            // if(typeof opts.Wlevel1.divClass === 'undefined'){
            //  console.log('insert in if');
            // }


            var prdiv_lw1 = $(opts.Wlevel1.prevDivClass).outerWidth(true);

            _lW1 = _W - (prdiv_lw1+ opts.Wlevel1.space);

            //applying Width on level 1 div
            $(opts.Wlevel1.divClass).css({width:_lW1 });


            //take left width after level one element
            _lW2 = _lW1 - ($(opts.Wlevel2.prevDivClass).outerWidth(true)+ opts.Wlevel2.space);
            //applying Width on level 2 div
            $(opts.Wlevel2.divClass).css({width:_lW2 });        

        };
        $(function() {
            performAdjust();
        });
        $(window).resize(function() {
            performAdjust();
        });

    }
})(jQuery);

How to Initialize it

// initialize adjust function for manage route
    $(document).ready(function (){
        adjust({
            headerClass : '.header',
            containerClass :'.container, .navContainer',
            Hlevel1: {space:0, divClass : '.viewport', prevDivClass : '#leftBreadcrumb'},

            Wlevel1 :{space:0, divClass : '.contentContainer', prevDivClass : '.navContainer'},
            Wlevel2 :{space:0, divClass : '.header-midsec', prevDivClass : '.navContainer'}
        })
    });

Initialize it again when the page came by ajax request

$(document).ready(function (){
  adjust({
    Hlevel1: {space:100, divClass : '.viewport1', prevDivClass : '.routeHead '},
  })
});

The Problem

When i initialize it again for other elements it will override all property. first time i initialize it for main page structure. Next time my page came from ajax request so underneath that structure some elements need dynamic width, height for adjust this i've to initialize it again but it will override all property.

I would like to make a condition if i'll calling this function again and not passing unused object and parameter then that will not run.

How can i achieve this please let me know

Thanks in advance and sorry for my english

Simply i just want to know if am calling a function again and again how to set a condition in my plugin that if am not calling that particular section is not run.

One more thing i've tried typeof but i can't understand how to handle it.

2 Answers 2

2

What you are actually trying to achieve is, if I understand correctly, overwriting the defaults with the passed options fields at the first time, but overriding last used values when doing it again.

What you would like to do is, simply, move out the defaults variable to the scope of the closure, outside the scope of the adjust function. This way the new incoming options fields would overwrite the object used previously, instead of overwriting the same hardcoded defaults each time.

Basically, you change:

adjust = function(options) {
    var defaults = { 
        headerClass: '',
        containerClass : ''
    };
    var opts = $.extend(defaults, options);

to:

var defaults = { 
        headerClass: '',
        containerClass : ''            
    };

adjust = function(options) {
    var opts = $.extend(defaults, options);

JSFiddle example: http://jsfiddle.net/MvxAj/1/

I have removed the XlevelY fields for readability. You may also want to consider using a more dynamic approach where those fields aren't hardcoded, to minimize code changes when you add another level, but that's a different case :)

Sign up to request clarification or add additional context in comments.

4 Comments

As @pebbl noticed, it's actually relying on both aspects of $.extend - returning the value AND modifying the first object. We should probably rely only on one of those :)
if i'll do by this way then it'll solve my problem. I'll check it first then i'll come here.
i've tested it according to your way and i got success. check out this fiddle jsfiddle.net/sarfarazdesigner/cSXAv/1 Only i've a doubt i can't understand it that when you see in console mode it will show same elements and not overriding? check out this image i.imgur.com/QLds6vV.jpg?3 please let me know
@TheMechanic don't worry about seeing the same output from both console.log calls here — this is because console.log actualy does NOT happen immediately and if you pass object reference to it, it will simply try to display the same object — therefore you see the later state of the object twice. If you want to see the object's state at the time of console.log, try converting it to string immediately. Try using: console.log(JSON.stringify(opts)); Now the two output lines are different, because you convert the object to a readable form at call-time, not at display-time.
1

possible solution

My guess as to what you need is just some conditional checks for particular values being set, however your code is rather awkward to read through, so working out what needs to be defined to trigger what action is a little difficult.

The main constant within your code seems to be that you define a specific selector for each element you are targeting, so you could just wrap each of the statements that affect a particular selector with an if:

if ( opts.containerClass ) {
  $(opts.containerClass).css({height:_lH});
}

You don't require typeof really for this because if you selectors are empty spaces, they aren't going to be very useful... and empty spaces are counted as false by an if statement.

However this wont take into account if you have any elements that rely on each other for size changes, your code logic and css will have to be aware of the dependancies between your elements, and apply your if statements accordingly.

further problem

The defaults object also adds a problem, due to the fact that if you merge in a set of defaults to an object you are testing for property existence, the properties in the default object will always appear set. You have three ways around this really.

  1. Create a test object before you merge in your defaults, then run all your if statements from this test object.
  2. Only use the defaults object the first time your code is called, subsequent calls then only rely on what you pass in.
  3. When you call the code later i.e. after ajax, pass in false values for the items you do not wish to change.

So as an example of 1, place this code before your defaults merge.

var test = {};
if ( options.containerClass ) {
  test.containerClass = true;
}
var opts = $.extend({}, defaults, options);

However it would seem a bit silly using default values if you don't need to use them, and possibly this is the case when you call after ajax; this leads us on to point 2:

if ( !adjust.alreadyCalled ) {
  var opts = $.extend(defaults, options);
  adjust.alreadyCalled = true;
}
else {
  opts = options;
}

Some people would possibly be right to complain about the above idea, because it would fundementally change the behaviour of your adjust method in an unexpected way. This is why I suggest point 3 — override the items you don't want — if you prefer.

$(document).ready(function(){
  adjust({
    containerClass: false,
    Hlevel1: {
     'space': 100, 
     'divClass': '.viewport1', 
     'prevDivClass': '.routeHead '
    }
  })
});

The downside to this though is that if you ever extend the items that this function can adjust, you will have to go about modifying all your calls to adjust to make sure that everything you want to override is falsed out.

a better way

Rather than work around what you already have, what I would recommend — as well as the addition of conditional statements — is to add a secondary parameter for adjust, e.g:

adjust = function(options, includeDefaults) {

This way you can tell if and when you want to use defaults, and obviously if you enable defaults, then all adjustments are likely to occur... if you don't enable defaults, you can then be more specific about what you want to adjust, because your conditional checking wont be confused by default values.

var opts;
if ( includeDefaults ) {
  opts = $.extend({}, defaults, options);
}
else {
  opts = options;
}

update

@ikari (+1) just made a good point which I failed to notice, you are infact not using $.extend correctly for a defaults merge. You would be better off using:

opts = $.extend({}, defaults, options);

This way you create a new object combining first the defaults and then your passed in options, rather than constantly modifying your defaults object. I've gone through and updated my code above to reflect this change.

2 Comments

i'll try according to you can you please tell me how to handle objects. How to check objects in condition without go for his string for example : if(opts.Hlevel1){//condition goes here} something like this let me know
@TheMechanic What you've typed there is fine for testing for the existence of a property on an object. The condition will execute if opts.Hlevel1 evaluates to true, which it will do for any 'non-false' value. False values in JavaScript are counted as 0, '', false, null, undefined, NaN... So any object {}, no matter it's content, is evaluated as true. Hope that makes sense?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.