1

Problem

I'm building an order form that has the ability to add new items. Each item row consist of something like quantity, unit price, description, and total. Everytime you want to add a new item, you click an action and a new row is inserted below the original with a set of blank fields. The problem I'm facing is when the browser contains a scroll bar and the items are near the bottom of the screen. When you add a new item, the new item appears below the view requiring the user to have to manually scroll the page.

What I'm looking for.

I'm looking for a jquery solution that will,

  • 1) detect the location of the previous item in the view.
  • 2) after a new item has been inserted into the page via ajax, do a nice animated scroll of the page bringing the newly created item back to the exact position of the previous item.

What I've tried.

<div id="lineItemContainer">
    <div class="tapestry-forminjector">
        <div><input type="text" name="quantity"/></div>
        <div><input type="text" name="unit price"/></div>
        <div><input type="text" name="description"/></div>
        <div><input type="text" name="total"/></div>
    </div>
</div>
<div id="buttonContainer"><input type="submit" value="Add New Item"/></div>

//This event handler listens for new rows and is fired once the new row has been added.

$("#lineItemContainer div.tapestry-forminjector").live(Tapestry.AJAXFORMLOOP_ROW_ADDED, function(event){
    // This provides zero animation and currently does not work. 
    var y = $(window).scrollTop();
$(window).scrollTop(y+176);
}

Thoughts I'm assuming the best solution would be to get the y view coordinate of the previous to last item once the new item has been added and then scroll the page until the last item is at the same y view coordinate. I'm just not sure how to accomplish this task.

Thanks in advance. Tapestry.AJAXFORMLOOP_ROW_ADDED event handler

UPDATE Requested by simon, the

$.widget("ui.tapestryFormInjector", {
        options : {
            show : "highlight"
        },

        _create : function() {
            this.element.addClass("tapestry-forminjector")
        },

        destroy : function() {
            this.element.removeClass("tapestry-forminjector");

            $.Widget.prototype.destroy.apply(this, arguments);
        },

        trigger : function() {
            var that = this, el = $("#" + this.options.element);

            var successHandler = function(data) {
                $(data).log("data");
                $.tapestry.utils.loadScriptsInReply(data, function() {
                    // Clone the FormInjector element (usually a div)
                    // to create the new element, that gets inserted
                    // before or after the FormInjector's element.

                    var newElement = el.clone(false);
                    newElement.attr("id", data.elementId);
                    newElement.html(data.content);

                    newElement = that.options.below ? el.after(newElement) : el
                            .before(newElement);

                    newElement.effect(that.options.show);

                    newElement.trigger(Tapestry.AJAXFORMLOOP_ROW_ADDED);
                });

            };

            $(this.options).log("this.options.url" + this.options.url)
            $.tapestry.utils.ajaxRequest({
                type : "POST",
                url : this.options.url,
                success : successHandler
            });
        }
    });
Code Junkie
  • 7,602
  • 26
  • 79
  • 141

2 Answers2

2

If I had understood the problem correctly.. In callback function, If you want pure JavaScript way without animation

 newElement.scrollIntoView(value) 
 // value = true, if you want to align with top else false

If you want jQuery way

.offset() calculates the position of an element relative to the document. Getting top value of element and moving scrollbar to that particular element with animation. It sets the vertical position of the scroll bar for matched element.

 $("html, body").animate({ scrollTop: $('#newElement').offset().top }, 1500);

Hope this helps. If I am wrong, please correct me

Exception
  • 8,111
  • 22
  • 85
  • 136
  • The animation was exactly what I was looking for. Do you think you could explain the code a little bit so I understand what it is doing a little bit better? – Code Junkie Feb 14 '13 at 16:08
  • 1
    The first clause sets the entire page as the active (moving) element. The second one says, "move the page to this element", and the third modifies the second to set the appropriate position based on its distance from the top of the viewport. – isherwood Feb 14 '13 at 16:10
  • Lets say I have additional content below, for example an audit trail. When would the scroll stop? At the base of the scroll or when the newElement hit's the top? – Code Junkie Feb 14 '13 at 16:16
0

$("html, body").animate({ scrollTop: $(document).height()-$(window).height() });

This will help you

For more details