0

I built this object with functions that scrolls text, but when i try to add an instance to another element the previous instances get overwritten with the config options of the new instance.

Here is a example on jsfiddle after the top animation finishes the text speed and all other config options are overwritten.

HTML Code:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Notes</title>
    <script src="jquery-2.1.js"></script>
</head>
<body style="margin: 0 auto;">
    <div class="scroll">
        <div class="scrollContainer">
            <div class="scrollText"></div>
        </div>
    </div>
    <div>
        <div>
            <div id="me"></div>
        </div>
    </div>
    <div>
        <div>
            <div id="try">I'll overwrite everything!</div>
        </div>
    </div>
    <script src="scroll.js"></script>
</body>
</html>

JavaScript/jQuery Code:

$(document).ready(function () {
    $(function () {
        var scroll = [];
        scroll = {
            config: {
                text: 'hello everybody',
                speed: 15000,
                container: $('.scrollText'),
                width: 250,
                parent: $('.scrollContainer'),
                parentContainer: $('.scroll'),
                textWidth: 0,
                totalWidth: 0
            },
            init: function (config) {
                $.extend(this.config, config);
                var self = this,
                    selfC = self.config,
                    selfE = selfC.container;
                console.log(selfE);
                selfE.html(scroll.config.text.trim());
                selfE.css({
                    display: 'inline-block'
                })
                selfC.textWidth = scroll.config.container.width();
                //console.log(scroll.config.textWidth);
                selfE.css({
                    width: selfC.textWidth + 10,
                        'margin-right': scroll.config.width,
                        'margin-left': scroll.config.width
                })
                selfC.totalWidth = selfE.outerWidth(true);
                selfC.parentContainer.css({
                    width: scroll.config.width,
                    overflow: 'hidden',
                    margin: '0 auto'
                })
                scroll.animate(selfE);
            },
            animate: function (elem) {
                var self = this,
                    selfC = self.config,
                    selfE = selfC.container;
                selfE.animate({
                    'margin-left': '-=' + (selfC.totalWidth - selfC.width)
                }, selfC.speed, function () {
                    selfE.css({
                        'margin-left': scroll.config.width
                    })
                    selfE.scrollText(selfC); //.speed -= 1000
                });
            }
        };
        $.fn.scrollText = function (config) {
            return this.each(function () {
                var obj = Object.create(scroll);
                obj.init({
                    text: config.text,
                    speed: config.speed,
                    width: config.width,
                    container: $(this),
                    parent: config.parent || $(this).parent(),
                    parentContainer: config.parentContainer || $(this).parent().parent()
                }, this)
            });
        }
        $('#me, .scrollText').scrollText({
            text: 'Help us update the names on our site by going to "Account" and selecting one of the options',
            width: 250,
            speed: 15000
        });
        $('div').last().scrollText({
            text: 'another acroll',
            speed: 5000,
            width: 50
        })
    }())
})

I need away to apply scrollText to as many elements with custom configuration without overwriting.

N.B. when calling .scrollText with more then one element as a selector it does work as in the code above but the config options are the same for all elements/instances

effy
  • 410
  • 8
  • 20

2 Answers2

2

Try redefine your scroll object as a Class

var Scroll = function () {
    this.config = {
        // initial config remain the same
    }
};

Scroll.prototype.init = function (config) {
    // init implementation remain the same
};

Scroll.prototype.animate = function (elem) {
    // animate implementation remain the same
};

Now, with this change, you can instantiate a new Scroll instance on your scrollText function like this:

$.fn.scrollText = function (config) {
    return this.each(function () {
        var obj = new Scroll(); // here is the change
        obj.init({
            text: config.text,
            speed: config.speed,
            width: config.width,
            container: $(this),
            parent: config.parent || $(this).parent(),
            parentContainer: config.parentContainer || $(this).parent().parent()
        }, this)
    });
}

the object passed as parameter to Object.create is used as a prototype to make a new object. If some attribute of parameter is an object or function, this attribute will be use as an reference to the original one.

Read more about Object.create here

Callebe
  • 1,087
  • 7
  • 18
0

Object.create won't work since the sub objects aka nested objects will still be a reference to the original object's sub-object, fixed up a nice prototype version should work good.

the fix uses $.extend and passes in a new object called config instead of using this.config which will overwrite the previous settings:

inif: function (config) {
    config = $.extend({}, this.config, config); //new object pulls defaults from this.config and overwrites it from params

    return this.setupHtml(config)//setup html
            .setupCss(config)//css 
            .animate(config, config.container)//animating. Note: always pass in that object so it don't use defaults;
}

here's the fiddle:

http://jsfiddle.net/0eqxqvec/3/

P.S. you could also rename the prototype config to defaults and then when init you create a new property called config an then you can use this.config, fiddle: http://jsfiddle.net/0eqxqvec/4/

I prefer using params though but that's just me call me crazy call me stupid.

Shiala
  • 486
  • 3
  • 8
  • What exactly do you mean by "Object.create will still be a reference to the original object"? – Bergi Sep 03 '14 at 17:57
  • I obviously did not express myself right, I am talking about nested objects, example: var a = {address: {name: 'shiya'}}; var b = Object.create(a); b.address.name = 'Not Shiya'; console.log(a.address.name); Will console 'Not Shiya' $.extend solves that – Shiala Sep 03 '14 at 18:05
  • Btw this question was not a duplicate since the user was simply asking for a better solution than Object.create and that's what he got – Shiala Sep 03 '14 at 18:09
  • Ok, yes, you mean that properties of an inherited object will reference the same sub-object as the original one - you should include that in your answer. But notice that the same applies for `$.extend` - you will need to use the recursion option. – Bergi Sep 03 '14 at 18:12
  • The recursion option is set to true by default, however if one passes in false as the first argument recursion will be off. if any of you wants to Google recursion go ahead and do so but don't get fooled by their 'did you mean question....' – Shiala Sep 03 '14 at 18:18
  • 1
    That's news to me. http://api.jquery.com/jQuery.extend/: "*The merge performed by $.extend() is not recursive by default; if a property of the first object is itself an object or array, it will be completely overwritten by a property with the same key in the second or subsequent object. The values are not merged.*" (You were referring to jQuery, right?) – Bergi Sep 03 '14 at 18:23
  • 1
    right, my bad I didn't read the documentation and just assumed it's like that by default since I always pass in an empty object (a common plugin development pattern) as first param, I guess that's why one should always read stuff before arguing about it. – Shiala Sep 03 '14 at 18:33
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/60565/discussion-between-shiala-and-bergi). – Shiala Sep 03 '14 at 18:34