Rectangle 27 2

To my knowledge, you can't skip an argument the way you seem to want to. That said, it seems you don't really want to skip one. The way to do this is change the way you're looking at the problem. What would work is to have a single argument that accepts either 'counter' or 'fasta2bed'. Changing the relevant lines in your code might produce something like:

import argparse
parser=argparse.ArgumentParser(
    usage="""python myscript.py {toolname} filename [-option]""",
    description='''Description.''',
    epilog="""Epilog.""")
parser.add_argument('toolname', choices=['counter', 'fasta2bed'], help='the name of the tool to be used')
parser.add_argument('filename', help='the input file name')
parser.add_argument('-l', '--long', action='store_true',     help='retrive a long summary file (default)')
parser.add_argument('-s', '--short', action='store_true', help='retrive a short summary file')
args=parser.parse_args()

You can check the choices for toolname by checking args.toolname:

if args.toolname == 'counter':
    print 'Running counter'
else:
    print 'Running fasta2bed'

Note that you'll need to use elif if you have more than 2 choices.

@chepner - Ah, yeah, copied and pasted too quickly ... Fixed now. Thanks!

Thank you very much! And how I can assign two different functions to counter e fasta2bed? I tried with an if statement but it doesen't work and always runs counter instead of fastabed :(

@Revo: You're on the correct course. Check what I added to my answer.

Great, now it works well! The last question I have is: can I add (in this way) an help for the explanation of what counter and fasta2bed (and the other tools I will add) do? Thank you very much GreenMatt :)

@Revo: As far as I know, there is no limit to the length of the usage message (that you defined when you instantiated the parser), or the help message for an argument. So - although it might be long - you can use those tools to do what you want. I have an application which has a usage message that would more than fill a 8.5" x 11" (or A4) page if a hardcopy was printed.

How to skip a positional argument in Python Argparse - Stack Overflow

python arguments argparse
Rectangle 27 35

just what i needed.. that "continue" for breaking only the current loop and not leaving the whole loop as break does.

Can you 'exit' a loop in PHP? - Stack Overflow

php loops
Rectangle 27 14

I've edited ionic lib to do something like that. But i couldn't do a JSFiddle or a Code Pen i Will give you the link to my modified ionic.css and ionic.bundle.js!

Just replace it with yours, start an ionic project blank. And put this HTML in it:

<body ng-app="starter">
       <ion-pane>
            <ion-header-bar class="bar-stable">
                <h1 class="title">Ionic Blank Starter</h1>
            </ion-header-bar>
            <ion-content>
                <ion-list show-delete="false" can-swipe="true" swipe-direction="both">
                    <ion-item href="#">
                        Item 1
                        <ion-option-button side="right" class="button-light icon ion-heart"></ion-option-button>
                        <ion-option-button side="right" class="button-light icon ion-email"></ion-option-button>
                        <ion-option-button side="left" class="button-assertive icon ion-trash-a"></ion-option-button>
                    </ion-item>
                    <ion-item href="#">
                        Item 2
                        <ion-option-button class="button-light icon ion-heart"></ion-option-button>
                        <ion-option-button class="button-light icon ion-email"></ion-option-button>
                        <ion-option-button class="button-assertive icon ion-trash-a"></ion-option-button>
                    </ion-item>
                </ion-list>
            </ion-content>
        </ion-pane>
  </body>

You can specify the wipe direction with left, right or both. And in the ion-options-button you can give it a side.

First change the ionOptionButton directive to create to div for the button, one left and one right

//added second div with class item-options-left for the left buttons

var ITEM_TPL_OPTION_BUTTONS =
        '<div class="item-options invisible">' +
        '</div>' + '<div class="item-options-left invisible">' + 
        '</div>';
IonicModule.directive('ionOptionButton', [function () {
    function stopPropagation(e) {
        e.stopPropagation();
    }
    return {
        restrict: 'E',
        require: '^ionItem',
        priority: Number.MAX_VALUE,
        compile: function ($element, $attr) {
            $attr.$set('class', ($attr['class'] || '') + ' button', true);
            return function ($scope, $element, $attr, itemCtrl) {

                if (!itemCtrl.optionsContainer) {
                    itemCtrl.optionsContainer = jqLite(ITEM_TPL_OPTION_BUTTONS);
                    itemCtrl.$element.append(itemCtrl.optionsContainer);
                }

                //[NEW] if it as an attribute side = 'left' put the button in the left container
                if ($attr.side === 'left') {
                    angular.element(itemCtrl.optionsContainer[1]).append($element);
                    itemCtrl.$element.addClass('item-left-editable');
                } else{
                    angular.element(itemCtrl.optionsContainer[0]).append($element);
                    itemCtrl.$element.addClass('item-right-editable');
                }

                //Don't bubble click up to main .item
                $element.on('click', stopPropagation);
            };
        }
    };
}]);

Add CSS to left buttons in ionic.css file

.item-options-left {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 1;
  height: 100%; }
.item-options-left .button {
  height: 100%;
  border: none;
  border-radius: 0;
  display: -webkit-inline-box;
  display: -webkit-inline-flex;
  display: -moz-inline-flex;
  display: -ms-inline-flexbox;
  display: inline-flex;
  -webkit-box-align: center;
  -ms-flex-align: center;
  -webkit-align-items: center;
  -moz-align-items: center;
  align-items: center; }
.item-options .button:before {
  margin: 0 auto; }

Now change the ion-list controller to accept swipe directions attribute

.controller('$ionicList', [
  '$scope',
  '$attrs',
  '$ionicListDelegate',
  '$ionicHistory',
function ($scope, $attrs, $ionicListDelegate, $ionicHistory) {
            var self = this;

            //[NEW] object with can-swipe attr and swipe-direction side attr, default direction is left
            var swipe = {
                isSwipeable: true,
                side: 'left'
            };
            var isReorderShown = false;
            var isDeleteShown = false;

            var deregisterInstance = $ionicListDelegate._registerInstance(
                self, $attrs.delegateHandle,
                function () {
                    return $ionicHistory.isActiveScope($scope);
                }
            );
            $scope.$on('$destroy', deregisterInstance);

            self.showReorder = function (show) {
                if (arguments.length) {
                    isReorderShown = !!show;
                }
                return isReorderShown;
            };

            self.showDelete = function (show) {
                if (arguments.length) {
                    isDeleteShown = !!show;
                }
                return isDeleteShown;
            };

            //[NEW] get swipe direction attribute and store it in a variable to access in other function
            self.canSwipeItems = function (can) {
                if (arguments.length) {
                    swipe.isSwipeable = !!can;
                    swipe.side = $attrs.swipeDirection;
                }
                return swipe;
            };

            self.closeOptionButtons = function () {
                self.listView && self.listView.clearDragEffects();
            };
}]);

To end, you should replace slideDrag function with this one, just search for it in ionic.bundle.js

//[NEW] add this var to the others in the function
var ITEM_OPTIONS_CLASS_RIGHT = 'item-options-left';

var SlideDrag = function (opts) {
        this.dragThresholdX = opts.dragThresholdX || 10;
        this.el = opts.el;
        this.item = opts.item;
        this.canSwipe = opts.canSwipe;
    };

    SlideDrag.prototype = new DragOp();

    SlideDrag.prototype.start = function (e) {
        var content, buttonsLeft, buttonsRight, offsetX, buttonsLeftWidth, buttonsRightWidth;

        if (!this.canSwipe().isSwipeable) {
            return;
        }

        if (e.target.classList.contains(ITEM_CONTENT_CLASS)) {
            content = e.target;
        } else if (e.target.classList.contains(ITEM_CLASS)) {
            content = e.target.querySelector('.' + ITEM_CONTENT_CLASS);
        } else {
            content = ionic.DomUtil.getParentWithClass(e.target, ITEM_CONTENT_CLASS);
        }

        // If we don't have a content area as one of our children (or ourselves), skip
        if (!content) {
            return;
        }

        // Make sure we aren't animating as we slide
        content.classList.remove(ITEM_SLIDING_CLASS);

        // Grab the starting X point for the item (for example, so we can tell whether it is open or closed to start)
        offsetX = parseFloat(content.style[ionic.CSS.TRANSFORM].replace('translate3d(', '').split(',')[0]) || 0;

        // Grab the buttons
        buttonsLeft = content.parentNode.querySelector('.' + ITEM_OPTIONS_CLASS);
        if (!buttonsLeft) {
            return;
        }

        //[NEW] get the Right buttons
        buttonsRight = content.parentNode.querySelector('.' + ITEM_OPTIONS_CLASS_RIGHT);
        if (!buttonsRight) {
            return;
        }

        // [NEW] added the same functionality to both sides, to make buttons visible when dragged
        if(e.gesture.direction === "left")
            buttonsLeft.classList.remove('invisible');
        else
            buttonsRight.classList.remove('invisible');

        //[NEW] added buttonRight and buttonLeft properties to currentDrag

        buttonsLeftWidth = buttonsLeft.offsetWidth;
        buttonsRightWidth = buttonsRight.offsetWidth;

        this._currentDrag = {
            buttonsLeft: buttonsLeft,
            buttonsRight: buttonsRight,
            buttonsLeftWidth: buttonsLeftWidth,
            buttonsRightWidth: buttonsRightWidth,
            content: content,
            startOffsetX: offsetX
        };
    };

    /**
     * Check if this is the same item that was previously dragged.
     */
    SlideDrag.prototype.isSameItem = function (op) {
        if (op._lastDrag && this._currentDrag) {
            return this._currentDrag.content == op._lastDrag.content;
        }
        return false;
    };

    SlideDrag.prototype.clean = function (isInstant) {
        var lastDrag = this._lastDrag;

        if (!lastDrag || !lastDrag.content) return;

        lastDrag.content.style[ionic.CSS.TRANSITION] = '';
        lastDrag.content.style[ionic.CSS.TRANSFORM] = '';
        if (isInstant) {
            lastDrag.content.style[ionic.CSS.TRANSITION] = 'none';
            makeInvisible();
            ionic.requestAnimationFrame(function () {
                lastDrag.content.style[ionic.CSS.TRANSITION] = '';
            });
        } else {
            ionic.requestAnimationFrame(function () {
                setTimeout(makeInvisible, 250);
            });
        }

        function makeInvisible() {
            lastDrag.buttonsLeft && lastDrag.buttonsLeft.classList.add('invisible');
            lastDrag.buttonsRight && lastDrag.buttonsRight.classList.add('invisible');
        }
    };

    SlideDrag.prototype.drag = ionic.animationFrameThrottle(function (e) {
        var buttonsLeftWidth;
        var buttonsRightWidth;

        // We really aren't dragging
        if (!this._currentDrag) {
            return;
        }

        // Check if we should start dragging. Check if we've dragged past the threshold,
        // or we are starting from the open state.
        if (!this._isDragging &&
            ((Math.abs(e.gesture.deltaX) > this.dragThresholdX) ||
                (Math.abs(this._currentDrag.startOffsetX) > 0))) {
            this._isDragging = true;
        }

        if (this._isDragging) {
            buttonsLeftWidth = this._currentDrag.buttonsLeftWidth;
            buttonsRightWidth = this._currentDrag.buttonsRightWidth;

            // Grab the new X point, capping it at zero
            //[NEW] added right swipe new position
            if (this.canSwipe().side === 'left' || (this.canSwipe().side === 'both' && e.gesture.direction === 'left'))
                var newX = Math.min(0, this._currentDrag.startOffsetX + e.gesture.deltaX);
            else if (this.canSwipe().side === 'right' || (this.canSwipe().side === 'both' && e.gesture.direction === 'right'))
                var newX = Math.max(0, this._currentDrag.startOffsetX + e.gesture.deltaX);

            var buttonsWidth = 0;
            if (e.gesture.direction === 'right')
                buttonsWidth = buttonsRightWidth;
            else
                buttonsWidth = buttonsLeftWidth;
            // If the new X position is past the buttons, we need to slow down the drag (rubber band style) 
            if (newX < -buttonsWidth) {
                // Calculate the new X position, capped at the top of the buttons
                newX = Math.min(-buttonsWidth, -buttonsWidth + (((e.gesture.deltaX + buttonsWidth) * 0.4)));
            }



            this._currentDrag.content.$$ionicOptionsOpen = newX !== 0;

            this._currentDrag.content.style[ionic.CSS.TRANSFORM] = 'translate3d(' + newX + 'px, 0, 0)';
            this._currentDrag.content.style[ionic.CSS.TRANSITION] = 'none';
        }
    });

    SlideDrag.prototype.end = function (e, doneCallback) {
        var self = this;

        // There is no drag, just end immediately
        if (!self._currentDrag) {
            doneCallback && doneCallback();
            return;
        }

        // If we are currently dragging, we want to snap back into place
        // The final resting point X will be the width of the exposed buttons
        var restingPoint;
        if (e.gesture.direction === 'left' && (this.canSwipe().side === 'left' || this.canSwipe().side === 'both'))
            restingPoint = -self._currentDrag.buttonsLeftWidth;
        if (e.gesture.direction === 'right' && (this.canSwipe().side === 'right' || this.canSwipe().side === 'both'))
            restingPoint = self._currentDrag.buttonsRightWidth;

        // Check if the drag didn't clear the buttons mid-point
        // and we aren't moving fast enough to swipe open
        var buttonsWidth = 0;
        if (e.gesture.direction === 'right') 
            buttonsWidth = self._currentDrag.buttonsRightWidth;
        else 
            buttonsWidth = self._currentDrag.buttonsLeftWidth;
        if (e.gesture.deltaX > -(buttonsWidth / 2)) {

            // If we are going left or right but too slow, or going right, go back to resting
            if ((e.gesture.direction == "left" || e.gesture.direction == "right")  && Math.abs(e.gesture.velocityX) < 0.3) {
                restingPoint = 0;
            } 

        }

        ionic.requestAnimationFrame(function () {
            if (restingPoint === 0) {
                self._currentDrag.content.style[ionic.CSS.TRANSFORM] = '';
                var buttonsLeft = self._currentDrag.buttonsLeft;
                var buttonsRight = self._currentDrag.buttonsRight;
                setTimeout(function () {
                    buttonsLeft && buttonsLeft.classList.add('invisible');
                    buttonsRight && buttonsRight.classList.add('invisible');
                }, 250);
            } else {
                self._currentDrag.content.style[ionic.CSS.TRANSFORM] = 'translate3d(' + restingPoint + 'px,0,0)';
            }
            self._currentDrag.content.style[ionic.CSS.TRANSITION] = '';


            // Kill the current drag
            if (!self._lastDrag) {
                self._lastDrag = {};
            }
            ionic.extend(self._lastDrag, self._currentDrag);
            if (self._currentDrag) {
                self._currentDrag.buttons = null;
                self._currentDrag.content = null;
            }
            self._currentDrag = null;

            // We are done, notify caller
            doneCallback && doneCallback();
        });
    };

My solution is not perfect, but it works. and there are others ways of doing this, i did it this way to understand better how Ionic works and how they do Ionic directives.

Any feedback is welcome, and with this you can try to make your own or improve this one.

This is awesome, thanks! It works great for me. There is only one minor thing - when you have buttons on both sides and trying swipe left/right, getting back to neutral position is a little hard. The only safe way to put it in neutral position is to scroll the whole list a little. Then it fits right back in perfectly.

Maybe you can implement something like one tap on item to put it in neutral position.

Fixed it. The problem is in the SlideDrag.prototype.end. The problematic line is - if (e.gesture.deltaX > -(self._currentDrag.buttonsWidth / 2)). There is no self_currentDrag.buttonsWidth. There is buttonsRightWidth and buttonsLeftWidth. Once that is fixed, swiping back to neutral position works like a magic. Thanks again for the great solution!

Thanks for the info @Dejan, can you just post here what you did, for me to update my answer.

Sure, so instead of this: if (e.gesture.deltaX > -(self._currentDrag.buttonsWidth / 2)) { put this: var buttonsWidth = 0; if (e.gesture.direction === 'right') buttonsWidth = self._currentDrag.buttonsRightWidth; else buttonsWidth = self._currentDrag.buttonsLeftWidth; if (e.gesture.deltaX > -(buttonsWidth / 2)) {

angularjs - How to swipe from left to right Ionic list item? - Stack O...

angularjs ionic-framework
Rectangle 27 14

I've edited ionic lib to do something like that. But i couldn't do a JSFiddle or a Code Pen i Will give you the link to my modified ionic.css and ionic.bundle.js!

Just replace it with yours, start an ionic project blank. And put this HTML in it:

<body ng-app="starter">
       <ion-pane>
            <ion-header-bar class="bar-stable">
                <h1 class="title">Ionic Blank Starter</h1>
            </ion-header-bar>
            <ion-content>
                <ion-list show-delete="false" can-swipe="true" swipe-direction="both">
                    <ion-item href="#">
                        Item 1
                        <ion-option-button side="right" class="button-light icon ion-heart"></ion-option-button>
                        <ion-option-button side="right" class="button-light icon ion-email"></ion-option-button>
                        <ion-option-button side="left" class="button-assertive icon ion-trash-a"></ion-option-button>
                    </ion-item>
                    <ion-item href="#">
                        Item 2
                        <ion-option-button class="button-light icon ion-heart"></ion-option-button>
                        <ion-option-button class="button-light icon ion-email"></ion-option-button>
                        <ion-option-button class="button-assertive icon ion-trash-a"></ion-option-button>
                    </ion-item>
                </ion-list>
            </ion-content>
        </ion-pane>
  </body>

You can specify the wipe direction with left, right or both. And in the ion-options-button you can give it a side.

First change the ionOptionButton directive to create to div for the button, one left and one right

//added second div with class item-options-left for the left buttons

var ITEM_TPL_OPTION_BUTTONS =
        '<div class="item-options invisible">' +
        '</div>' + '<div class="item-options-left invisible">' + 
        '</div>';
IonicModule.directive('ionOptionButton', [function () {
    function stopPropagation(e) {
        e.stopPropagation();
    }
    return {
        restrict: 'E',
        require: '^ionItem',
        priority: Number.MAX_VALUE,
        compile: function ($element, $attr) {
            $attr.$set('class', ($attr['class'] || '') + ' button', true);
            return function ($scope, $element, $attr, itemCtrl) {

                if (!itemCtrl.optionsContainer) {
                    itemCtrl.optionsContainer = jqLite(ITEM_TPL_OPTION_BUTTONS);
                    itemCtrl.$element.append(itemCtrl.optionsContainer);
                }

                //[NEW] if it as an attribute side = 'left' put the button in the left container
                if ($attr.side === 'left') {
                    angular.element(itemCtrl.optionsContainer[1]).append($element);
                    itemCtrl.$element.addClass('item-left-editable');
                } else{
                    angular.element(itemCtrl.optionsContainer[0]).append($element);
                    itemCtrl.$element.addClass('item-right-editable');
                }

                //Don't bubble click up to main .item
                $element.on('click', stopPropagation);
            };
        }
    };
}]);

Add CSS to left buttons in ionic.css file

.item-options-left {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 1;
  height: 100%; }
.item-options-left .button {
  height: 100%;
  border: none;
  border-radius: 0;
  display: -webkit-inline-box;
  display: -webkit-inline-flex;
  display: -moz-inline-flex;
  display: -ms-inline-flexbox;
  display: inline-flex;
  -webkit-box-align: center;
  -ms-flex-align: center;
  -webkit-align-items: center;
  -moz-align-items: center;
  align-items: center; }
.item-options .button:before {
  margin: 0 auto; }

Now change the ion-list controller to accept swipe directions attribute

.controller('$ionicList', [
  '$scope',
  '$attrs',
  '$ionicListDelegate',
  '$ionicHistory',
function ($scope, $attrs, $ionicListDelegate, $ionicHistory) {
            var self = this;

            //[NEW] object with can-swipe attr and swipe-direction side attr, default direction is left
            var swipe = {
                isSwipeable: true,
                side: 'left'
            };
            var isReorderShown = false;
            var isDeleteShown = false;

            var deregisterInstance = $ionicListDelegate._registerInstance(
                self, $attrs.delegateHandle,
                function () {
                    return $ionicHistory.isActiveScope($scope);
                }
            );
            $scope.$on('$destroy', deregisterInstance);

            self.showReorder = function (show) {
                if (arguments.length) {
                    isReorderShown = !!show;
                }
                return isReorderShown;
            };

            self.showDelete = function (show) {
                if (arguments.length) {
                    isDeleteShown = !!show;
                }
                return isDeleteShown;
            };

            //[NEW] get swipe direction attribute and store it in a variable to access in other function
            self.canSwipeItems = function (can) {
                if (arguments.length) {
                    swipe.isSwipeable = !!can;
                    swipe.side = $attrs.swipeDirection;
                }
                return swipe;
            };

            self.closeOptionButtons = function () {
                self.listView && self.listView.clearDragEffects();
            };
}]);

To end, you should replace slideDrag function with this one, just search for it in ionic.bundle.js

//[NEW] add this var to the others in the function
var ITEM_OPTIONS_CLASS_RIGHT = 'item-options-left';

var SlideDrag = function (opts) {
        this.dragThresholdX = opts.dragThresholdX || 10;
        this.el = opts.el;
        this.item = opts.item;
        this.canSwipe = opts.canSwipe;
    };

    SlideDrag.prototype = new DragOp();

    SlideDrag.prototype.start = function (e) {
        var content, buttonsLeft, buttonsRight, offsetX, buttonsLeftWidth, buttonsRightWidth;

        if (!this.canSwipe().isSwipeable) {
            return;
        }

        if (e.target.classList.contains(ITEM_CONTENT_CLASS)) {
            content = e.target;
        } else if (e.target.classList.contains(ITEM_CLASS)) {
            content = e.target.querySelector('.' + ITEM_CONTENT_CLASS);
        } else {
            content = ionic.DomUtil.getParentWithClass(e.target, ITEM_CONTENT_CLASS);
        }

        // If we don't have a content area as one of our children (or ourselves), skip
        if (!content) {
            return;
        }

        // Make sure we aren't animating as we slide
        content.classList.remove(ITEM_SLIDING_CLASS);

        // Grab the starting X point for the item (for example, so we can tell whether it is open or closed to start)
        offsetX = parseFloat(content.style[ionic.CSS.TRANSFORM].replace('translate3d(', '').split(',')[0]) || 0;

        // Grab the buttons
        buttonsLeft = content.parentNode.querySelector('.' + ITEM_OPTIONS_CLASS);
        if (!buttonsLeft) {
            return;
        }

        //[NEW] get the Right buttons
        buttonsRight = content.parentNode.querySelector('.' + ITEM_OPTIONS_CLASS_RIGHT);
        if (!buttonsRight) {
            return;
        }

        // [NEW] added the same functionality to both sides, to make buttons visible when dragged
        if(e.gesture.direction === "left")
            buttonsLeft.classList.remove('invisible');
        else
            buttonsRight.classList.remove('invisible');

        //[NEW] added buttonRight and buttonLeft properties to currentDrag

        buttonsLeftWidth = buttonsLeft.offsetWidth;
        buttonsRightWidth = buttonsRight.offsetWidth;

        this._currentDrag = {
            buttonsLeft: buttonsLeft,
            buttonsRight: buttonsRight,
            buttonsLeftWidth: buttonsLeftWidth,
            buttonsRightWidth: buttonsRightWidth,
            content: content,
            startOffsetX: offsetX
        };
    };

    /**
     * Check if this is the same item that was previously dragged.
     */
    SlideDrag.prototype.isSameItem = function (op) {
        if (op._lastDrag && this._currentDrag) {
            return this._currentDrag.content == op._lastDrag.content;
        }
        return false;
    };

    SlideDrag.prototype.clean = function (isInstant) {
        var lastDrag = this._lastDrag;

        if (!lastDrag || !lastDrag.content) return;

        lastDrag.content.style[ionic.CSS.TRANSITION] = '';
        lastDrag.content.style[ionic.CSS.TRANSFORM] = '';
        if (isInstant) {
            lastDrag.content.style[ionic.CSS.TRANSITION] = 'none';
            makeInvisible();
            ionic.requestAnimationFrame(function () {
                lastDrag.content.style[ionic.CSS.TRANSITION] = '';
            });
        } else {
            ionic.requestAnimationFrame(function () {
                setTimeout(makeInvisible, 250);
            });
        }

        function makeInvisible() {
            lastDrag.buttonsLeft && lastDrag.buttonsLeft.classList.add('invisible');
            lastDrag.buttonsRight && lastDrag.buttonsRight.classList.add('invisible');
        }
    };

    SlideDrag.prototype.drag = ionic.animationFrameThrottle(function (e) {
        var buttonsLeftWidth;
        var buttonsRightWidth;

        // We really aren't dragging
        if (!this._currentDrag) {
            return;
        }

        // Check if we should start dragging. Check if we've dragged past the threshold,
        // or we are starting from the open state.
        if (!this._isDragging &&
            ((Math.abs(e.gesture.deltaX) > this.dragThresholdX) ||
                (Math.abs(this._currentDrag.startOffsetX) > 0))) {
            this._isDragging = true;
        }

        if (this._isDragging) {
            buttonsLeftWidth = this._currentDrag.buttonsLeftWidth;
            buttonsRightWidth = this._currentDrag.buttonsRightWidth;

            // Grab the new X point, capping it at zero
            //[NEW] added right swipe new position
            if (this.canSwipe().side === 'left' || (this.canSwipe().side === 'both' && e.gesture.direction === 'left'))
                var newX = Math.min(0, this._currentDrag.startOffsetX + e.gesture.deltaX);
            else if (this.canSwipe().side === 'right' || (this.canSwipe().side === 'both' && e.gesture.direction === 'right'))
                var newX = Math.max(0, this._currentDrag.startOffsetX + e.gesture.deltaX);

            var buttonsWidth = 0;
            if (e.gesture.direction === 'right')
                buttonsWidth = buttonsRightWidth;
            else
                buttonsWidth = buttonsLeftWidth;
            // If the new X position is past the buttons, we need to slow down the drag (rubber band style) 
            if (newX < -buttonsWidth) {
                // Calculate the new X position, capped at the top of the buttons
                newX = Math.min(-buttonsWidth, -buttonsWidth + (((e.gesture.deltaX + buttonsWidth) * 0.4)));
            }



            this._currentDrag.content.$$ionicOptionsOpen = newX !== 0;

            this._currentDrag.content.style[ionic.CSS.TRANSFORM] = 'translate3d(' + newX + 'px, 0, 0)';
            this._currentDrag.content.style[ionic.CSS.TRANSITION] = 'none';
        }
    });

    SlideDrag.prototype.end = function (e, doneCallback) {
        var self = this;

        // There is no drag, just end immediately
        if (!self._currentDrag) {
            doneCallback && doneCallback();
            return;
        }

        // If we are currently dragging, we want to snap back into place
        // The final resting point X will be the width of the exposed buttons
        var restingPoint;
        if (e.gesture.direction === 'left' && (this.canSwipe().side === 'left' || this.canSwipe().side === 'both'))
            restingPoint = -self._currentDrag.buttonsLeftWidth;
        if (e.gesture.direction === 'right' && (this.canSwipe().side === 'right' || this.canSwipe().side === 'both'))
            restingPoint = self._currentDrag.buttonsRightWidth;

        // Check if the drag didn't clear the buttons mid-point
        // and we aren't moving fast enough to swipe open
        var buttonsWidth = 0;
        if (e.gesture.direction === 'right') 
            buttonsWidth = self._currentDrag.buttonsRightWidth;
        else 
            buttonsWidth = self._currentDrag.buttonsLeftWidth;
        if (e.gesture.deltaX > -(buttonsWidth / 2)) {

            // If we are going left or right but too slow, or going right, go back to resting
            if ((e.gesture.direction == "left" || e.gesture.direction == "right")  && Math.abs(e.gesture.velocityX) < 0.3) {
                restingPoint = 0;
            } 

        }

        ionic.requestAnimationFrame(function () {
            if (restingPoint === 0) {
                self._currentDrag.content.style[ionic.CSS.TRANSFORM] = '';
                var buttonsLeft = self._currentDrag.buttonsLeft;
                var buttonsRight = self._currentDrag.buttonsRight;
                setTimeout(function () {
                    buttonsLeft && buttonsLeft.classList.add('invisible');
                    buttonsRight && buttonsRight.classList.add('invisible');
                }, 250);
            } else {
                self._currentDrag.content.style[ionic.CSS.TRANSFORM] = 'translate3d(' + restingPoint + 'px,0,0)';
            }
            self._currentDrag.content.style[ionic.CSS.TRANSITION] = '';


            // Kill the current drag
            if (!self._lastDrag) {
                self._lastDrag = {};
            }
            ionic.extend(self._lastDrag, self._currentDrag);
            if (self._currentDrag) {
                self._currentDrag.buttons = null;
                self._currentDrag.content = null;
            }
            self._currentDrag = null;

            // We are done, notify caller
            doneCallback && doneCallback();
        });
    };

My solution is not perfect, but it works. and there are others ways of doing this, i did it this way to understand better how Ionic works and how they do Ionic directives.

Any feedback is welcome, and with this you can try to make your own or improve this one.

This is awesome, thanks! It works great for me. There is only one minor thing - when you have buttons on both sides and trying swipe left/right, getting back to neutral position is a little hard. The only safe way to put it in neutral position is to scroll the whole list a little. Then it fits right back in perfectly.

Maybe you can implement something like one tap on item to put it in neutral position.

Fixed it. The problem is in the SlideDrag.prototype.end. The problematic line is - if (e.gesture.deltaX > -(self._currentDrag.buttonsWidth / 2)). There is no self_currentDrag.buttonsWidth. There is buttonsRightWidth and buttonsLeftWidth. Once that is fixed, swiping back to neutral position works like a magic. Thanks again for the great solution!

Thanks for the info @Dejan, can you just post here what you did, for me to update my answer.

Sure, so instead of this: if (e.gesture.deltaX > -(self._currentDrag.buttonsWidth / 2)) { put this: var buttonsWidth = 0; if (e.gesture.direction === 'right') buttonsWidth = self._currentDrag.buttonsRightWidth; else buttonsWidth = self._currentDrag.buttonsLeftWidth; if (e.gesture.deltaX > -(buttonsWidth / 2)) {

angularjs - How to swipe from left to right Ionic list item? - Stack O...

angularjs ionic-framework
Rectangle 27 3

If you really want to skip cells containing formulas, you could use this example as a start. The code assumes that only formulas start with an equals sign. Edit: expanding the example with the ranges in the question.

Sub example()
    Dim source As Range
    Dim target As Range
    Set source = ActiveSheet.Range("A1:B6")
    Set target = ActiveSheet.Range("D1:E6")
    copy_non_formulas source:=source, target:=target

    'Extended example using the ranges posted in the question
    'For the sake of formatting, I omitted the fully qualified
    'range names.
    copy_non_formulas source:=Range("H1124:AT1173"), target:=Range("H529:AT578")
    copy_non_formulas source:=Range("H1275:AT1284"), target:=Range("H580:AT589")       
End Sub


Public Sub copy_non_formulas(source As Range, target As Range)
    'Assumes that all formulas start with '=' and all non formulas do not
    Dim i As Long
    Dim j As Long
    Dim c As Range

    For i = 1 To source.Rows.Count
        For j = 1 To source.Columns.Count
            Set c = source(RowIndex:=i, ColumnIndex:=j)
            If Left(c.Formula, 1) <> "=" Then
                target(RowIndex:=i, ColumnIndex:=j).Value = c.Value
            End If
        Next j
    Next i
End Sub

thanks frank, this code will do the trick, can I set multiple sources and targets considering I am working with multiple ranges? This loop works good with one defined range but I am working with multiple ranges on this sheet

Yes, just call the procedure with any two ranges. I'll add some more example to the answer.

I had to modify the code slightly in order for it to paste special, I am getting the right behaviour except the cells on the target page show a value of 'TRUE' if the condition is met, it isn't pasting the values. See my modification on your post, can you see any reason why it would paste the condition rather than the values in the source cells?

What are you trying to do? Just copy the values in the cells?

I'm getting the script to check the cells in the source sheet for formulas, and if the source sheet contains numbered values rather than formulas, I need it to copy those values across to the target range, its currently copying / pasting but its pasting TRUE rather than the actual numbers themselves. It seems im missing something from within the code that tells it if the condition is true, than perform a copy / paste on the values themselves.

Excel VBA Copy / Paste macro: Ignore cells with Formulas - Stack Overf...

excel excel-vba
Rectangle 27 1

@Herman Schaaf Your solution is great but when you double click it skips a few zooms :D So I have made a solution + smoothZoom out I can't take all the credit I have edited JesseDobbelaere's code from jsfiddle.net It's a mix of yours and Jesse's code.

function smoothZoom(map, level, cnt, mode)
{
    if(mode == true)
    {
        if (cnt >= level) {
            return;
        }
        else
        {
            if((maxZoomOut + 2) <= cnt)
            {
                var z = google.maps.event.addListener(map, 'zoom_changed', function(event)
                {
                    google.maps.event.removeListener(z);
                    map.setCenter(marker.getPosition());
                    smoothZoom(map, level, cnt + 1, true);
                });
                setTimeout(function(){map.setZoom(cnt);}, timeOut);
            }
            else
            {
                map.setZoom(cnt);
                smoothZoom(map, level, cnt + 1, true);
            }
        }
    }
    else 
    {
        if (cnt < level) {
            return;
        }
        else
        {
            var z = google.maps.event.addListener(map, 'zoom_changed', function(event)
            {
                google.maps.event.removeListener(z);
                map.setCenter(marker.getPosition());
                smoothZoom(map, level, cnt - 1, false);
            });
            if(maxZoomIn - 2 <= cnt)
            {
                map.setZoom(cnt);
            }
            else
            {
                setTimeout(function(){map.setZoom(cnt);}, timeOut);
            }
        }
    }
}

I have made few more variables like timeOut and maxZoomIn Out... you can find full code on jsfiddle http://jsfiddle.net/dexy86/9afy9/

javascript - How to zoom in smoothly on a marker in Google Maps? - Sta...

javascript google-maps
Rectangle 27 1

@Herman Schaaf Your solution is great but when you double click it skips a few zooms :D So I have made a solution + smoothZoom out I can't take all the credit I have edited JesseDobbelaere's code from jsfiddle.net It's a mix of yours and Jesse's code.

function smoothZoom(map, level, cnt, mode)
{
    if(mode == true)
    {
        if (cnt >= level) {
            return;
        }
        else
        {
            if((maxZoomOut + 2) <= cnt)
            {
                var z = google.maps.event.addListener(map, 'zoom_changed', function(event)
                {
                    google.maps.event.removeListener(z);
                    map.setCenter(marker.getPosition());
                    smoothZoom(map, level, cnt + 1, true);
                });
                setTimeout(function(){map.setZoom(cnt);}, timeOut);
            }
            else
            {
                map.setZoom(cnt);
                smoothZoom(map, level, cnt + 1, true);
            }
        }
    }
    else 
    {
        if (cnt < level) {
            return;
        }
        else
        {
            var z = google.maps.event.addListener(map, 'zoom_changed', function(event)
            {
                google.maps.event.removeListener(z);
                map.setCenter(marker.getPosition());
                smoothZoom(map, level, cnt - 1, false);
            });
            if(maxZoomIn - 2 <= cnt)
            {
                map.setZoom(cnt);
            }
            else
            {
                setTimeout(function(){map.setZoom(cnt);}, timeOut);
            }
        }
    }
}

I have made few more variables like timeOut and maxZoomIn Out... you can find full code on jsfiddle http://jsfiddle.net/dexy86/9afy9/

javascript - How to zoom in smoothly on a marker in Google Maps? - Sta...

javascript google-maps
Rectangle 27 1

@Herman Schaaf Your solution is great but when you double click it skips a few zooms :D So I have made a solution + smoothZoom out I can't take all the credit I have edited JesseDobbelaere's code from jsfiddle.net It's a mix of yours and Jesse's code.

function smoothZoom(map, level, cnt, mode)
{
    if(mode == true)
    {
        if (cnt >= level) {
            return;
        }
        else
        {
            if((maxZoomOut + 2) <= cnt)
            {
                var z = google.maps.event.addListener(map, 'zoom_changed', function(event)
                {
                    google.maps.event.removeListener(z);
                    map.setCenter(marker.getPosition());
                    smoothZoom(map, level, cnt + 1, true);
                });
                setTimeout(function(){map.setZoom(cnt);}, timeOut);
            }
            else
            {
                map.setZoom(cnt);
                smoothZoom(map, level, cnt + 1, true);
            }
        }
    }
    else 
    {
        if (cnt < level) {
            return;
        }
        else
        {
            var z = google.maps.event.addListener(map, 'zoom_changed', function(event)
            {
                google.maps.event.removeListener(z);
                map.setCenter(marker.getPosition());
                smoothZoom(map, level, cnt - 1, false);
            });
            if(maxZoomIn - 2 <= cnt)
            {
                map.setZoom(cnt);
            }
            else
            {
                setTimeout(function(){map.setZoom(cnt);}, timeOut);
            }
        }
    }
}

I have made few more variables like timeOut and maxZoomIn Out... you can find full code on jsfiddle http://jsfiddle.net/dexy86/9afy9/

javascript - How to zoom in smoothly on a marker in Google Maps? - Sta...

javascript google-maps
Rectangle 27 7

This is the code for alias based on Todd Hodes solution

alias mtargets='make -qp | awk -F":" "/^[a-zA-Z0-9][^$#\/\t=]*:([^=]|$)/ {split(\$1,A,/ /);for(i in A)print A[i]}"'

makefile - List goals/targets in GNU make that contain variables in th...

makefile gnu-make
Rectangle 27 9

The most simple solution that I see is to override global functions describe and it to make them accept third optional argument, which has to be a boolean or a function returning a boolean - to tell whether or not current suite/spec should be executed. When overriding we should check if this third optional arguments resolves to true, and if it does, then we call xdescribe/xit (or ddescribe/iit depending on Jasmine version), which are Jasmine's methods to skip suite/spec, istead of original describe/it. This block has to be executed before the tests, but after Jasmine is included to the page. In Karma just move this code to a file and include it before test files in karma.conf.js. Here is the code:

(function (global) {

  // save references to original methods
  var _super = {
    describe: global.describe,
    it: global.it
  };

  // override, take third optional "disable"
  global.describe = function (name, fn, disable) {
    var disabled = disable;
    if (typeof disable === 'function') {
      disabled = disable();
    }

    // if should be disabled - call "xdescribe" (or "ddescribe")
    if (disable) {
      return global.xdescribe.apply(this, arguments);
    }

    // otherwise call original "describe"
    return _super.describe.apply(this, arguments);
  };

  // override, take third optional "disable"
  global.it = function (name, fn, disable) {
    var disabled = disable;
    if (typeof disable === 'function') {
      disabled = disable();
    }

    // if should be disabled - call "xit" (or "iit")
    if (disable) {
      return global.xit.apply(this, arguments);
    }

    // otherwise call original "it"
    return _super.it.apply(this, arguments);
  };

}(window));
describe('foo', function () {

  it('should foo 1 ', function () {
    expect(true).toBe(true);
  });

  it('should foo 2', function () {
    expect(true).toBe(true);
  }); 

}, true); // disable suite

describe('bar', function () {

  it('should bar 1 ', function () {
    expect(true).toBe(true);
  });

  it('should bar 2', function () {
    expect(true).toBe(true);
  }, function () {
    return true; // disable spec
  });

});

I've also stumbled upon this issue where the idea was to add a chain method .when() for describe and it, which will do pretty much the same I've described above. It may look nicer but is a bit harder to implement.

describe('foo', function () {

  it('bar', function () {
    // ...
  }).when(anything);      

}).when(something);

If you are really interested in this second approach, I'll be happy to play with it a little bit more and try to implement chain .when().

Jasmine uses third argument as a timeout option (see docs), so my code sample is replacing this feature, which is not ok. I like @milanlempera and @MarcoCI answers better, mine seems kinda hacky and not intuitive. I'll try to update my solution anyways soon not to break compatibilty with Jasmine default features.

Great. I used it to forbid fdescribe and fit in build env. Just override fdescribe and fit and throw exception.

Conditionally ignore individual tests with Karma / Jasmine - Stack Ove...

jasmine karma-runner karma-jasmine
Rectangle 27 2

Actually I think it might make the code faster. Here is the code for the first function:

bool biconditional(bool a, bool b)
{
    return (a && b) || (!a && !b);
}

bool biconditional_trick(bool a, bool b)
{
    return a == b;
}
biconditional(bool, bool):
        mov     eax, esi
        xor     eax, 1
        xor     eax, edi
        ret
biconditional_trick(bool, bool):
        cmp     dil, sil
        sete    al
        ret
-O3  -Wall -fno-verbose-asm -march=haswell

Clearly you can shave off 1 instruction. It's interesting that gcc doesn't do this optimization. You might want to drop them an e-mail and ask why: https://gcc.gnu.org/lists.html

Edit: the other answer makes a good point: logical expressions can be evaluated faster by trimming unnecessary parts. To demonstrate, I've rewritten the code to use calls to functions that return bool instead of bool arguments:

bool fa();
bool fb();

bool biconditional_with_function()
{
    return (fa() && fb()) || (!fa() && !fb());
}

bool biconditional_with_function_trick()
{
    return fa() == fb();
}

Here is the assembly:

biconditional_with_function():
        sub     rsp, 8
        call    fa()
        test    al, al
        je      .L7
        call    fb()
        test    al, al
        jne     .L10
.L7:
        call    fa()
        mov     edx, eax
        xor     eax, eax
        test    dl, dl
        je      .L14
.L10:
        add     rsp, 8
        ret
.L14:
        call    fb()
        add     rsp, 8
        xor     eax, 1
        ret
biconditional_with_function_trick():
        push    rbx
        call    fa()
        mov     ebx, eax
        call    fb()
        cmp     bl, al
        pop     rbx
        sete    al
        ret

You can see that the code generated for biconditional_with_function uses jumps to skip the second half of the expression if the first half is true. Interestingly when the second half is evaluated, fa() and fb() are called overall twice since the compiler doesn't know if they always return the same result. If that is the case, the code should be rewritten by saving the evaluated results in their own variables:

bool biconditional_with_function_rewritten()
{
    bool a = fa();
    bool b = fb();
    return (a && b) || (!a && !b);
}
biconditional_with_function_rewritten():
        push    rbx
        call    fa()
        mov     ebx, eax
        call    fb()
        xor     eax, 1
        xor     eax, ebx
        pop     rbx
        ret

We can see they are almost identical, just the 1 instruction difference remains, giving the "trick" method a slight advantage.

For the converse nonimplication, we can see that indeed GCC will avoid evaluating the second operator when logical operators are used, but not when the < operator is used:

bool fa();
bool fb();

bool converse_nonimplication()
{
    return !fa() && fb();
}

bool converse_nonimplication_trick()
{
    return fa() < fb();
}
converse_nonimplication():
        sub     rsp, 8
        call    fa()
        test    al, al
        je      .L5
        xor     eax, eax
        add     rsp, 8
        ret
.L5:
        add     rsp, 8
        jmp     fb()
converse_nonimplication_trick():
        push    rbx
        call    fa()
        mov     ebx, eax
        call    fb()
        cmp     al, bl
        pop     rbx
        seta    al
        ret

Huh, indeed. For the first example, there's an old missed-optimization bug report for GCC, though the code that gets generated now is already much better than it was back then. It's not as simple as "fewer instructions is faster", so it might be worth checking the actual instruction costs for both versions, but unless they're exactly equally fast, there's a missed optimisation in one or the other.

c++ - Comparison operators on booleans trick - Stack Overflow

c++ boolean comparison-operators boolean-operations
Rectangle 27 25

Probably you have problem on the server side. Could you append your question with the code of DynamicGridData action which you currently use. The action should have filters as the parameter.

Some parts of your current code are definitively wrong. For example jqGrid is the jQuery plugin. So the methods of jQuery will be extended with the main jqGrid method which you use as jQuery("#list").jqGrid(...);. So after the initializing of jqGrid jQuery("#list").jqGrid will be a function. In you code (the last statement) you overwrite the jQuery("#list").jqGrid method with the object { search: { ... } }. What you should do instead is

jQuery.extend(jQuery.jgrid.search, {
    odata : ['equal', 'not equal','contains']
});

like for example here is described how to overwrite the emptyrecords default value. You don't need to include the values which are already the same in the default jqGrid settings.

Moreover if you use searchoptions: { sopt: ['eq', 'ne', 'cn']} on all searchable columns you don't need to do the change.

In the text of your question you don't explained what you want to do. Your current code is so that you use the filter Message equal to true at the initial grid loading. Strange is that there are no column with the name Message in the grid. If you want just send some additional information to the server you should better use postData parameter:

postData: {Message:true}
imgpath
multipleSearch
sortable: true, search: true, sorttype: 'text', autoFit: true, stype:'text', align: 'left'

UPDATED: The original code of the Phil Haack demo is very old and it use LINQ to SQL. Like I wrote before (see here) Entity Framework (EF) allows to use sorting, paging and filtering/searching without any AddOns like LINQ Dynamic Query Library in form System.Linq.Dynamic. So I made the demo you you which is modification of the the Phil Haack demo to EF.

Because you use the old version of Visual Studio (VS2008 with ASP.NET MVC 2.0) I made the demo also in VS2008.

You can download my VS2008 demo from here and VS2010 demo here.

In the code I show (additionally to the usage of Advanced Searching and Toolbar Searching in ASP.NET MVC 2.0) how to return exception information from ASP.NET MVC in JSON format and how to catch the information with the loadError method and display the corresponding error message.

To construct the Where statement from the ObjectQuery represented EF object I define the following helper class:

public class Filters {
    public enum GroupOp {
        AND,
        OR
    }
    public enum Operations {
        eq, // "equal"
        ne, // "not equal"
        lt, // "less"
        le, // "less or equal"
        gt, // "greater"
        ge, // "greater or equal"
        bw, // "begins with"
        bn, // "does not begin with"
        //in, // "in"
        //ni, // "not in"
        ew, // "ends with"
        en, // "does not end with"
        cn, // "contains"
        nc  // "does not contain"
    }
    public class Rule {
        public string field { get; set; }
        public Operations op { get; set; }
        public string data { get; set; }
    }

    public GroupOp groupOp { get; set; }
    public List<Rule> rules { get; set; }
    private static readonly string[] FormatMapping = {
        "(it.{0} = @p{1})",                 // "eq" - equal
        "(it.{0} <> @p{1})",                // "ne" - not equal
        "(it.{0} < @p{1})",                 // "lt" - less than
        "(it.{0} <= @p{1})",                // "le" - less than or equal to
        "(it.{0} > @p{1})",                 // "gt" - greater than
        "(it.{0} >= @p{1})",                // "ge" - greater than or equal to
        "(it.{0} LIKE (@p{1}+'%'))",        // "bw" - begins with
        "(it.{0} NOT LIKE (@p{1}+'%'))",    // "bn" - does not begin with
        "(it.{0} LIKE ('%'+@p{1}))",        // "ew" - ends with
        "(it.{0} NOT LIKE ('%'+@p{1}))",    // "en" - does not end with
        "(it.{0} LIKE ('%'+@p{1}+'%'))",    // "cn" - contains
        "(it.{0} NOT LIKE ('%'+@p{1}+'%'))" //" nc" - does not contain
    };
    internal ObjectQuery<T> FilterObjectSet<T> (ObjectQuery<T> inputQuery) where T : class {
        if (rules.Count <= 0)
            return inputQuery;

        var sb = new StringBuilder();
        var objParams = new List<ObjectParameter>(rules.Count);

        foreach (Rule rule in rules) {
            PropertyInfo propertyInfo = typeof (T).GetProperty (rule.field);
            if (propertyInfo == null)
                continue; // skip wrong entries

            if (sb.Length != 0)
                sb.Append(groupOp);

            var iParam = objParams.Count;
            sb.AppendFormat(FormatMapping[(int)rule.op], rule.field, iParam);

            // TODO: Extend to other data types
            objParams.Add(String.Compare(propertyInfo.PropertyType.FullName,
                                         "System.Int32", StringComparison.Ordinal) == 0
                              ? new ObjectParameter("p" + iParam, Int32.Parse(rule.data))
                              : new ObjectParameter("p" + iParam, rule.data));
        }

        ObjectQuery<T> filteredQuery = inputQuery.Where (sb.ToString ());
        foreach (var objParam in objParams)
            filteredQuery.Parameters.Add (objParam);

        return filteredQuery;
    }
}

In the example I use only two datatypes integer (Edm.Int32) and string (Edm.String). You can easy expand the example to use more types based as above on the propertyInfo.PropertyType.FullName value.

The controller action which provide the data to the jqGrid will be pretty simple:

public JsonResult DynamicGridData(string sidx, string sord, int page, int rows, bool _search, string filters)
{

    var context = new HaackOverflowEntities();
    var serializer = new JavaScriptSerializer();
    Filters f = (!_search || string.IsNullOrEmpty (filters)) ? null : serializer.Deserialize<Filters> (filters);
    ObjectQuery<Question> filteredQuery =
        (f == null ? context.Questions : f.FilterObjectSet (context.Questions));
    filteredQuery.MergeOption = MergeOption.NoTracking; // we don't want to update the data
    var totalRecords = filteredQuery.Count();

    var pagedQuery = filteredQuery.Skip ("it." + sidx + " " + sord, "@skip",
                                        new ObjectParameter ("skip", (page - 1) * rows))
                                 .Top ("@limit", new ObjectParameter ("limit", rows));
    // to be able to use ToString() below which is NOT exist in the LINQ to Entity
    var queryDetails = (from item in pagedQuery
                        select new { item.Id, item.Votes, item.Title }).ToList();

    return Json(new {
                    total = (totalRecords + rows - 1) / rows,
                    page,
                    records = totalRecords,
                    rows = (from item in queryDetails
                            select new[] {
                                item.Id.ToString(),
                                item.Votes.ToString(),
                                item.Title
                            }).ToList()
                });
}

To send the exception information to the jqGrid in JSON form I replaced the standard [HandleError] attribute of the controller (HomeController) to the [HandleJsonException] which I defined as the following:

// to send exceptions as json we define [HandleJsonException] attribute
public class ExceptionInformation {
    public string Message { get; set; }
    public string Source { get; set; }
    public string StackTrace { get; set; }
}
public class HandleJsonExceptionAttribute : ActionFilterAttribute {
    // next class example are modification of the example from
    // the http://www.dotnetcurry.com/ShowArticle.aspx?ID=496
    public override void OnActionExecuted(ActionExecutedContext filterContext) {
        if (filterContext.HttpContext.Request.IsAjaxRequest() && filterContext.Exception != null) {
            filterContext.HttpContext.Response.StatusCode =
                (int)System.Net.HttpStatusCode.InternalServerError;

            var exInfo = new List<ExceptionInformation>();
            for (Exception ex = filterContext.Exception; ex != null; ex = ex.InnerException) {
                PropertyInfo propertyInfo = ex.GetType().GetProperty ("ErrorCode");
                exInfo.Add(new ExceptionInformation() {
                    Message = ex.Message,
                    Source = ex.Source,
                    StackTrace = ex.StackTrace
                });
            }
            filterContext.Result = new JsonResult() {Data=exInfo};
            filterContext.ExceptionHandled = true;
        }
    }
}

On the client side I used the following JavaScript code:

var myGrid = $('#list'),
    decodeErrorMessage = function(jqXHR, textStatus, errorThrown) {
        var html, errorInfo, i, errorText = textStatus + '\n' + errorThrown;
        if (jqXHR.responseText.charAt(0) === '[') {
            try {
                errorInfo = $.parseJSON(jqXHR.responseText);
                errorText = "";
                for (i=0; i<errorInfo.length; i++) {
                   if (errorText.length !== 0) {
                       errorText += "<hr/>";
                   }
                   errorText += errorInfo[i].Source + ": " + errorInfo[i].Message;
                }
            }
            catch (e) { }
        } else {
            html = /<body.*?>([\s\S]*)<\/body>/.exec(jqXHR.responseText);
            if (html !== null && html.length > 1) {
                errorText = html[1];
            }
        }
        return errorText;
    };
myGrid.jqGrid({
    url: '<%= Url.Action("DynamicGridData") %>',
    datatype: 'json',
    mtype: 'POST',
    colNames: ['Id', 'Votes', 'Title'],
    colModel: [
        { name: 'Id', index: 'Id', key: true, width: 40,
            searchoptions: { sopt: ['eq', 'ne', 'lt', 'le', 'gt', 'ge'] }
        },
        { name: 'Votes', index: 'Votes', width: 40,
            searchoptions: { sopt: ['eq', 'ne', 'lt', 'le', 'gt', 'ge'] }
        },
        { name: 'Title', index: 'Title', width: 400,
            searchoptions: { sopt: ['cn', 'nc', 'bw', 'bn', 'eq', 'ne', 'ew', 'en', 'lt', 'le', 'gt', 'ge'] }
        }
    ],
    pager: '#pager',
    rowNum: 10,
    rowList: [5, 10, 20, 50],
    sortname: 'Id',
    sortorder: 'desc',
    rownumbers: true,
    viewrecords: true,
    altRows: true,
    altclass: 'myAltRowClass',
    height: '100%',
    jsonReader: { cell: "" },
    caption: 'My first grid',
    loadError: function(jqXHR, textStatus, errorThrown) {
        // remove error div if exist
        $('#' + this.id + '_err').remove();
        // insert div with the error description before the grid
        myGrid.closest('div.ui-jqgrid').before(
            '<div id="' + this.id + '_err" style="max-width:'+this.style.width+
            ';"><div class="ui-state-error ui-corner-all" style="padding:0.7em;float:left;"><span class="ui-icon ui-icon-alert" style="float:left; margin-right: .3em;"></span><span style="clear:left">' +
                        decodeErrorMessage(jqXHR, textStatus, errorThrown) + '</span></div><div style="clear:left"/></div>')
    },
    loadComplete: function() {
        // remove error div if exist
        $('#' + this.id + '_err').remove();
    }
});
myGrid.jqGrid('navGrid', '#pager', { add: false, edit: false, del: false },
              {}, {}, {}, { multipleSearch: true, overlay: false });
myGrid.jqGrid('filterToolbar', { stringResult: true, searchOnEnter: true, defaultSearch: 'cn' });
myGrid.jqGrid('navButtonAdd', '#pager',
            { caption: "Filter", title: "Toggle Searching Toolbar",
                buttonicon: 'ui-icon-pin-s',
                onClickButton: function() { myGrid[0].toggleToolbar(); }
            });

As the result if one types any non-numeric text (like 'ttt') in the searching toolbar one receive exception the controller action code (in Int32.Parse(rule.data)). One the client side one will see the following message:

I send from the controller to the jqgrid the information about all internal exceptions. So for example, the error in connection to the SQL server will looks like

In the real world one verify the users input and throws exception with application oriented error message. I used in the demo specially no such kind of validation to show that all kind of exception will be cached and display by jqGrid.

UPDATED 2: In the answer you will find the modified VS2010 demo (downloadable from here) which demonstrate the usage of jQuery UI Autocomplete. Another answer extend the code more to export the grid contain in Excel format.

@Sue: First of all I moved the code which you posted from the answer to the question. Do you use some common Database to the example or one own? I am busy now, but I'll try to correct your code later. Is the usage of LINQ to SQL is important for you or an Entity Framework (EF) database access is exactly so interesting? I ask because in EF it is easier to create dynamic queries based only on text input strings like you as has in case of jqGrid.

@Sue: If you remove multipleSearch:true searching option then the searching dialog will send _search, searchField, searchString, searchOper (the case is important) parameter in the request to the server. Without multipleSearch:true the format of the searching toolbar will be other like: parameters send to the server will be like the column names (column2 or/and column2). So one use mostly multipleSearch:true and convert in the server method the filters parameter to object with JavaScriptSerializer or DataContractJsonSerializer.

@Sue: My main idea is that the usage of ObjectQuery<T> in case of Entity Framework is better as the usage of IQueryable<T> because IQueryable<T> not support string parameters which you receive as input from jqGrid. If you use IQueryable<T> you will have to include in your project System.Linq.Dynamic.dll or the source code of LINQ Dynamic Query Library like tpeczek do (it is more as 4000 rows of code). The usage of ObjectQuery<T> is more effective in case of the usage of Entity Framework. It is my main statement.

@Learning: The above code do this. See the code of DynamicGridData . You can remove some parts of the code. If you are beginner I recommend you to consider exactly whether you really need server side paging. Client side paging/sorting/filtering works quickly enough for some 1000 of rows. Try the demo and this one with 4000 and 40000 rows

@Learning: Please write more exactly what you need. ASP.NET MVC is still ASP.NET. You asked about an example "in asp.net". What technology you you exactly? For example another answer provides an example of usage ASHX (IHttpHandler with ProcessRequest and IsReusable). Probably it's what you are looking for?

Sign up for our newsletter and get our top new questions delivered to your inbox (see an example).

entity framework - ASP.NET MVC 2.0 Implementation of searching in jqgr...

entity-framework asp.net-mvc-2 search jqgrid linq-to-entities
Rectangle 27 1

Sorry, but I don't see any implementation of paging in your code. You calculate the number of records which need be skipped and save it in startIndex, but you don't use startIndex later. Your current code just get data from DataTable and returns all items of the table. You need to skip startIndex items. For example you can start for loop from i = startIndex instead of i = 0.

In general it would be more effective to construct SELECT statement in SqlCommand which uses TOP construct or use STORED PROCEDURE like described in the answer (see another answer too). In the way your server code will get from the SQL server only one page of data instead of fetching all records of data and returning only one page.

UPDATED: I would rewrite your client code to something like the following

$(document).ready(function () {
    var templateDate = {
            width: 80,
            fixed: true,
            sorttype: "date",
            formatter: "date",
            formatoptions: { srcformat: "m/d/Y", newformat: "m/d/Y" }
        },
        templateInt = { width: 55, fixed: true, sorttype: "integer" },
        templateText = {
            width: 200,
            cellattr: function () {
                return 'style="white-space: normal!important;'
            }
        },
        mygrid = $("#RptUpload");

    // create the grid without filling it (datatype: "local")
    mygrid.jqGrid({
        datatype: "local", // to revent initial loading of the grid
        postData: {
            bReload: true,
            Year: function () { return $("#Year").val(); },
            Month: function () { return $("#Month").val(); }
        },
        url: '@Url.Action("DMEUploadDetailsList", "Reports")',
        jsonReader: { repeatitems: false, root: "DataRows" },
        colNames: [ "@VirtuOxAdmin.DMEUploadDetails_Grid_RptUpload_OrderID",
                    "@VirtuOxAdmin.DMEUploadDetails_Grid_RptUpload_CompanyName",
                    "@VirtuOxAdmin.DMEUploadDetails_Grid_RptUpload_PatientID",
                    "@VirtuOxAdmin.DMEUploadDetails_Grid_RptUpload_PatientName",
                    "@VirtuOxAdmin.DMEUploadDetails_Grid_RptUpload_DOB",
                    "@VirtuOxAdmin.DMEUploadDetails_Grid_RptUpload_Insurance",
                    "@VirtuOxAdmin.DMEUploadDetails_Grid_RptUpload_UploadDate"
        ],
        colModel: [
            { name: "ReadingID", template: templateInt },
            { name: "CompanyName", template: templateText },
            { name: "PatientID", template: templateInt },
            { name: "PatientName", template: templateText },
            { name: "DOB", template: templateDate },
            { name: "InsuranceType", width: 150, template: templateText },
            { name: "UploadDate", template: templateDate }
        ],
        cmTemplate: { align: "center" },
        rowNum: 20,
        rowList: [20, 50, 100, 200],
        pager: "#UploadPager",
        caption: "@VirtuOxAdmin.DMEUploadDetails_Grid_RptUpload_Title",
        viewrecords: true,
        height: "auto",
        width: 770,
        hidegrid: false,
        headertitles: true,
        loadError: function (xhr, status, error) {
            alert(status + " " + error);
        }
    });
    mygrid.navGrid("#UploadPager",
        { edit: false, add: false, del: false, search: false, refresh: false });
    mygrid.closest(".ui-jqgrid").hide(); // hide the grid

    $("#rptRefresh").click(function (e) {
        var Form = $("form[id=FrmDMEUploadDetails]");
        e.preventDefault();
        Form.validate();
        if (Form.valid()) {
            RemoveValidatioMessages();
            mygrid.jqGrid("setGridParam", { datatype: "json" })
                .trigger("reloadGrid", [{page: 1}])
                .closest(".ui-jqgrid").show(); // show the grid;
        } else {
            mygrid.clearGridData();
            mygrid.closest(".ui-jqgrid").hide(); // hide the grid
        }
        $(".chzn-select-deselect").trigger("liszt:updated");
        return false;
    });
});

The grid will be created with datatype: "local", so the url and postData will be ignored. After that it seems to me the usage of bReload property in postData and on the server side seems me unneeded. Nevertheless I included bReload still in the JavaScript code till you remove it from the server code.

Additionally I simplified the colModel by usage of column templates (cmTemplate option of jqGrid and template property of colModel). See the old answer for more information. I removed also some unneeded options of jqGrid which values are default (see "Default" column in the documentation of options).

About usage of new versions of STORED PROCEDURE (pc_GetUploadDetail in your code) you can consider to introduction new version (like pc_GetUploadDetailPaged) which supports more parameters. It will not break existing code which uses the old procedure, but you can still use sorting and paging of data on SQL Server instead of getting all query results to web server and implementing sorting and paging in C#.

Sorry, I forgot to update the paging code in problem statement. Well about updating stored procedures I am not allowed to do so as old application still in use. We are upgrading the project technology. So we cant alter the stored procedures in any way as it will affect the application in use. I have updated the problem statement to to include the paging code & elaborated on last two sentences of problem statement. Please have a look.

@Shaggy: I think that the current problem is on the client side. You don't posted currently how you use DefineGrid. The usage of postData: Form.serialize() is also unclear: which form you use how you set all values and so on. Typically one use datatype: "local" initially in grid to have no loading before the user set the filter. Then is the user click reload grid one can call setGridParam to set datatype: "json", set values of the form. Then one calls .trigger("reloadGrid").

Ohh! Sorry again, I just updated server side action method code let me update the grid definition & add script to show how I m using DefineGrid(). & I am not using Form.serialize() to pass values anymore.

I hope the code updatetd is now clear to you. As you can see loadComplete event I am trying to make bReload postData parameter false so that when user clicks paging or sorting I can get data from session instead of SQL server. But postData parameter bReload is not getting overrded in loadComplete as I m not triggering reload there. Is this wrong way of doing so?

asp.net mvc 4 - jqGrid url not getting called with server side paging ...

asp.net-mvc-4 jqgrid
Rectangle 27 2

I like @iWerner's generator function idea. One small change to his code and it does what the question asked for.

def readlines(filename):
    f = open(filename)
    # discard first lines that start with '#'
    for line in f:
        if not line.lstrip().startswith("#"):
            break
    yield line

    for line in f:
        yield line
for line in readlines("data.txt"):
    # do things
    pass

But here is a different approach. This is almost very simple. The idea is that we open the file, and get a file object, which we can use as an iterator. Then we pull the lines we don't want out of the iterator, and just return the iterator. This would be ideal if we always knew how many lines to skip. The problem here is we don't know how many lines we need to skip; we just need to pull lines and look at them. And there is no way to put a line back into the iterator, once we have pulled it.

So: open the iterator, pull lines and count how many have the leading '#' character; then use the .seek() method to rewind the file, pull the correct number again, and return the iterator.

One thing I like about this: you get the actual file object back, with all its methods; you can just use this instead of open() and it will work in all cases. I renamed the function to open_my_text() to reflect this.

Instead of f.readline() I could have used f.next() (for Python 2.x) or next(f) (for Python 3.x) but I wanted to write it so it was portable to any Python.

You can't put a line back into an iterator. But, you can open a file twice, and get two iterators; given the way file caching works, the second iterator is almost free. If we imagine a file with a megabyte of '#' lines at the top, this version would greatly outperform the previous version that calls f.seek(0).

def open_my_text(filename):
    # open the same file twice to get two file objects
    # (We are opening the file read-only so this is safe.)
    ftemp = open(filename, "rt")
    f = open(filename, "rt")

    # use ftemp to look at lines, then discard from f
    for line in ftemp:
        if not line.lstrip().startswith("#"):
            break
        f.readline()

    # return file object with comment lines pre-skipped
    return f

This version is much better than the previous version, and it still returns a full file object with all its methods.

Instead of count, why not use f.tell() in your loop to save the actual place in the file? Replace count = 0 with loc = 0, count += 1 with loc = f.tell(), and f.seek(0) with f.seek(loc) and remove your for _ in range(count) loop altogether.

I like the suggestion, but I just tried it and it doesn't work. The .tell() method does not track with the iterator; my short test file got slurped in completely and .tell() returned the end-of-file every time I called it. If .tell() did track with the iterator, I'd absolutely do it your way; it's cleaner. My code is messier, but has the advantage of actually working... :-)

python - More pythonic way of skipping header lines - Stack Overflow

python
Rectangle 27 2

I like @iWerner's generator function idea. One small change to his code and it does what the question asked for.

def readlines(filename):
    f = open(filename)
    # discard first lines that start with '#'
    for line in f:
        if not line.lstrip().startswith("#"):
            break
    yield line

    for line in f:
        yield line
for line in readlines("data.txt"):
    # do things
    pass

But here is a different approach. This is almost very simple. The idea is that we open the file, and get a file object, which we can use as an iterator. Then we pull the lines we don't want out of the iterator, and just return the iterator. This would be ideal if we always knew how many lines to skip. The problem here is we don't know how many lines we need to skip; we just need to pull lines and look at them. And there is no way to put a line back into the iterator, once we have pulled it.

So: open the iterator, pull lines and count how many have the leading '#' character; then use the .seek() method to rewind the file, pull the correct number again, and return the iterator.

One thing I like about this: you get the actual file object back, with all its methods; you can just use this instead of open() and it will work in all cases. I renamed the function to open_my_text() to reflect this.

Instead of f.readline() I could have used f.next() (for Python 2.x) or next(f) (for Python 3.x) but I wanted to write it so it was portable to any Python.

You can't put a line back into an iterator. But, you can open a file twice, and get two iterators; given the way file caching works, the second iterator is almost free. If we imagine a file with a megabyte of '#' lines at the top, this version would greatly outperform the previous version that calls f.seek(0).

def open_my_text(filename):
    # open the same file twice to get two file objects
    # (We are opening the file read-only so this is safe.)
    ftemp = open(filename, "rt")
    f = open(filename, "rt")

    # use ftemp to look at lines, then discard from f
    for line in ftemp:
        if not line.lstrip().startswith("#"):
            break
        f.readline()

    # return file object with comment lines pre-skipped
    return f

This version is much better than the previous version, and it still returns a full file object with all its methods.

Instead of count, why not use f.tell() in your loop to save the actual place in the file? Replace count = 0 with loc = 0, count += 1 with loc = f.tell(), and f.seek(0) with f.seek(loc) and remove your for _ in range(count) loop altogether.

I like the suggestion, but I just tried it and it doesn't work. The .tell() method does not track with the iterator; my short test file got slurped in completely and .tell() returned the end-of-file every time I called it. If .tell() did track with the iterator, I'd absolutely do it your way; it's cleaner. My code is messier, but has the advantage of actually working... :-)

python - More pythonic way of skipping header lines - Stack Overflow

python
Rectangle 27 5

Your code is incomplete as you're nowhere showing how disableBeanValidation is implemented and how you're passing the #{param[skipBeanValidation]} around.

<f:validateBean disabled="#{param.skipBeanValidation}" />

...

<h:commandLink value="Edit" action="#{buyerBacking.edit}"/>
    <f:param name="skipBeanValidation" value="true" />
</h:commandLink>

Please note that #{param.skipBeanValidation} is quite different from #{param[skipBeanValidation]} (but the same as #{param['skipBeanValidation']}). Also please note that the desired request parameter to skip the bean validation is been passed as a HTTP request parameter, exactly as is been expected by #{param}.

I have updated the code in my question. I have coded the same way you suggested, but as asked in the question, selecting cancel and then selecting edit causing indexoutof bound exception.

The stacktrace would be helpful.

Added the stacktrace. Please let me know if additional information is needed. Even if I hardcode the disabled value to true. It works only for the first time. When cancel is clicked and then edit, the validation takes place even though disabled is true. For the Cancel method I am returning an empty String.

That's a pretty serious problem. Are you creating components dynamically? Are you using binding somewhere?

There is no usage of binding in our code. And also the components are rendered based on a flag but not created dynamically.

jsf 2 - Skip validation conditionally JSF - Stack Overflow

jsf-2
Rectangle 27 5

Your code is incomplete as you're nowhere showing how disableBeanValidation is implemented and how you're passing the #{param[skipBeanValidation]} around.

<f:validateBean disabled="#{param.skipBeanValidation}" />

...

<h:commandLink value="Edit" action="#{buyerBacking.edit}"/>
    <f:param name="skipBeanValidation" value="true" />
</h:commandLink>

Please note that #{param.skipBeanValidation} is quite different from #{param[skipBeanValidation]} (but the same as #{param['skipBeanValidation']}). Also please note that the desired request parameter to skip the bean validation is been passed as a HTTP request parameter, exactly as is been expected by #{param}.

I have updated the code in my question. I have coded the same way you suggested, but as asked in the question, selecting cancel and then selecting edit causing indexoutof bound exception.

The stacktrace would be helpful.

Added the stacktrace. Please let me know if additional information is needed. Even if I hardcode the disabled value to true. It works only for the first time. When cancel is clicked and then edit, the validation takes place even though disabled is true. For the Cancel method I am returning an empty String.

That's a pretty serious problem. Are you creating components dynamically? Are you using binding somewhere?

There is no usage of binding in our code. And also the components are rendered based on a flag but not created dynamically.

jsf 2 - Skip validation conditionally JSF - Stack Overflow

jsf-2
Rectangle 27 1

Yes you should skip optimizing for the unit test. Optimization when required usually makes the code more complex. Aim for simplicity. If you optimize for the unit test you may actually de-optimize for production.

If performance is really bad in the unit test, you may need to look at your design. Test in the application to see if performance is equally bad before optimizing.

EDIT: De-optimization is likely to occur when the data being handled varies is size. This is most likely to occur will classes that work with sets of data. Response may be linear, but originally slow, compared to geometric and originally fast. If the unit test uses a small set of data, then the geometric solution may be chosen for the unit test. When production hits the class with a large set of data performance tanks.

Sorting algorithms are a classic case for this kind of behavior and resulting de-optimizations. Many other algorithms have similar characteristics.

EDIT2: My most successful optimization was the sort routine for a report where data was stored on disk in a memory mapped file. The sort times were reasonable with moderate data sizes which did not require disk access. With larger sized data sets it could take days to process the data. Initial timings of the report showed; data selection 3 minutes, data sorting 3 days, and reporting 3 minutes. Investigation of the sort showed that it was a fully unoptimized bubble sort (n-1 full passes for a data set of size n), roughly n square in big O notation. Changing the sorting algorithm reduced the sort time for this report to 3 minutes. I would not have expected a unit test to cover this case, and the original code was as simple (fast) as you could get for small sets. The replacement was much more complex and slower for very small sets, but handled large sets faster with a more linear curve, n log n in big O notation. (Note: no optimization was attempted until we had metrics.)

In practice, I aim for a ten-fold improvement of a routine which takes at least 50% of the module run-time. Achieving this level of optimization for a routine using 55% of the run-time will save 50% of the total run-time.

I hope this isn't a stupid question, but how could optimizing for the unit test deoptimize for production? Say you heavily optimize (maybe using some of the techniques in this thread) and you're able to cut down execution time by 50% or more. Wouldn't this translate to faster execution time in the application environment? I'm not sure I understand.

Ah, I see....however, it would be logical to unit-test classes in different ways, no? If a class takes multiple types of data, or data of multiple sizes, it would be logical to test for these cases. At least, that's what I'd do (but I'm kind of geeky, so I love stuff like that). I can, however, understand time constraints being an issue.

@lunchmeat317: This quickly becomes impractical for any reasonably large size of data. I would expect unit test to use small sets (less than 10).

It took a while (a long while) to really get this. I understood what you were saying, but only after looking at big-O notation do I really understand what you mean. It's possible (and I would imagine, recommended) to unit test with different ranges of data - 10, 100, 1000, 10000, etc....but once you get past those constraints, testing becomes expensive. Good answer.

oop - Is optimizing a class for a unit test good practice, or is it pr...

unit-testing oop class optimization premature-optimization
Rectangle 27 4

The main problem in the usage of my old demo from the old answer is in the line of code

this.processing = true;

jqGrid initializes now this to the DOM element of the table ($("#list")[0]) in calls of the most callback functions. So the above line have to be fixed to

options.processing = true;

There are other small changes which should be implemented also. The most important is the calling of $.unformat.date to decode of all fields used by the formatter "date".

The new demo used jqGrid 4.4.1 you can find here.

var lastSel,
    mydata = [
        {id: "1",  invdate: "2007-10-01", name: "test",   note: "note",   amount: "200.00", tax: "10.00", closed: true,  ship_via: "TN", total: "210.00"},
        {id: "2",  invdate: "2007-10-02", name: "test2",  note: "note2",  amount: "300.00", tax: "20.00", closed: false, ship_via: "FE", total: "320.00"},
        {id: "3",  invdate: "2007-09-01", name: "test3",  note: "note3",  amount: "400.00", tax: "30.00", closed: false, ship_via: "FE", total: "430.00"},
        {id: "4",  invdate: "2007-10-04", name: "test4",  note: "note4",  amount: "200.00", tax: "10.00", closed: true,  ship_via: "TN", total: "210.00"},
        {id: "5",  invdate: "2007-10-31", name: "test5",  note: "note5",  amount: "300.00", tax: "20.00", closed: false, ship_via: "FE", total: "320.00"},
        {id: "6",  invdate: "2007-09-06", name: "test6",  note: "note6",  amount: "400.00", tax: "30.00", closed: false, ship_via: "FE", total: "430.00"},
        {id: "7",  invdate: "2007-10-04", name: "test7",  note: "note7",  amount: "200.00", tax: "10.00", closed: true,  ship_via: "TN", total: "210.00"},
        {id: "8",  invdate: "2007-10-03", name: "test8",  note: "note8",  amount: "300.00", tax: "20.00", closed: false, ship_via: "FE", total: "320.00"},
        {id: "9",  invdate: "2007-09-01", name: "test9",  note: "note9",  amount: "400.00", tax: "30.00", closed: false, ship_via: "TN", total: "430.00"},
        {id: "10", invdate: "2007-09-08", name: "test10", note: "note10", amount: "500.00", tax: "30.00", closed: true,  ship_via: "TN", total: "530.00"},
        {id: "11", invdate: "2007-09-08", name: "test11", note: "note11", amount: "500.00", tax: "30.00", closed: false, ship_via: "FE", total: "530.00"},
        {id: "12", invdate: "2007-09-10", name: "test12", note: "note12", amount: "500.00", tax: "30.00", closed: false, ship_via: "FE", total: "530.00"}
    ],
    grid = $("#list"),
    getColumnIndex = function (columnName) {
        var cm = $(this).jqGrid('getGridParam', 'colModel'), i, l = cm.length;
        for (i = 0; i < l; i++) {
            if ((cm[i].index || cm[i].name) === columnName) {
                return i; // return the colModel index
            }
        }
        return -1;
    },
    onclickSubmitLocal = function (options, postdata) {
        var $this = $(this), grid_p = this.p,
            idname = grid_p.prmNames.id,
            grid_id = this.id,
            id_in_postdata = grid_id + "_id",
            rowid = postdata[id_in_postdata],
            addMode = rowid === "_empty",
            oldValueOfSortColumn,
            new_id,
            tr_par_id,
            colModel = grid_p.colModel,
            cmName,
            iCol,
            cm;

        // postdata has row id property with another name. we fix it:
        if (addMode) {
            // generate new id
            new_id = $.jgrid.randId();
            while ($("#" + new_id).length !== 0) {
                new_id = $.jgrid.randId();
            }
            postdata[idname] = String(new_id);
        } else if (typeof postdata[idname] === "undefined") {
            // set id property only if the property not exist
            postdata[idname] = rowid;
        }
        delete postdata[id_in_postdata];

        // prepare postdata for tree grid
        if (grid_p.treeGrid === true) {
            if (addMode) {
                tr_par_id = grid_p.treeGridModel === 'adjacency' ? grid_p.treeReader.parent_id_field : 'parent_id';
                postdata[tr_par_id] = grid_p.selrow;
            }

            $.each(grid_p.treeReader, function (i) {
                if (postdata.hasOwnProperty(this)) {
                    delete postdata[this];
                }
            });
        }

        // decode data if there encoded with autoencode
        if (grid_p.autoencode) {
            $.each(postdata, function (n, v) {
                postdata[n] = $.jgrid.htmlDecode(v); // TODO: some columns could be skipped
            });
        }

        // save old value from the sorted column
        oldValueOfSortColumn = grid_p.sortname === "" ? undefined : grid.jqGrid('getCell', rowid, grid_p.sortname);

        // save the data in the grid
        if (grid_p.treeGrid === true) {
            if (addMode) {
                $this.jqGrid("addChildNode", new_id, grid_p.selrow, postdata);
            } else {
                $this.jqGrid("setTreeRow", rowid, postdata);
            }
        } else {
            if (addMode) {
                // we need unformat all date fields before calling of addRowData
                for (cmName in postdata) {
                    if (postdata.hasOwnProperty(cmName)) {
                        iCol = getColumnIndex.call(this, cmName);
                        if (iCol >= 0) {
                            cm = colModel[iCol];
                            if (cm && cm.formatter === "date") {
                                postdata[cmName] = $.unformat.date.call(this, postdata[cmName], cm);
                            }
                        }
                    }
                }
                $this.jqGrid("addRowData", new_id, postdata, options.addedrow);
            } else {
                $this.jqGrid("setRowData", rowid, postdata);
            }
        }

        if ((addMode && options.closeAfterAdd) || (!addMode && options.closeAfterEdit)) {
            // close the edit/add dialog
            $.jgrid.hideModal("#editmod" + grid_id, {
                gb: "#gbox_" + grid_id,
                jqm: options.jqModal,
                onClose: options.onClose
            });
        }

        if (postdata[grid_p.sortname] !== oldValueOfSortColumn) {
            // if the data are changed in the column by which are currently sorted
            // we need resort the grid
            setTimeout(function () {
                $this.trigger("reloadGrid", [{current: true}]);
            }, 100);
        }

        // !!! the most important step: skip ajax request to the server
        options.processing = true;
        return {};
    },
    editSettings = {
        //recreateForm: true,
        jqModal: false,
        reloadAfterSubmit: false,
        closeOnEscape: true,
        savekey: [true, 13],
        closeAfterEdit: true,
        onclickSubmit: onclickSubmitLocal
    },
    addSettings = {
        //recreateForm: true,
        jqModal: false,
        reloadAfterSubmit: false,
        savekey: [true, 13],
        closeOnEscape: true,
        closeAfterAdd: true,
        onclickSubmit: onclickSubmitLocal
    },
    delSettings = {
        // because I use "local" data I don't want to send the changes to the server
        // so I use "processing:true" setting and delete the row manually in onclickSubmit
        onclickSubmit: function (options, rowid) {
            var $this = $(this), grid_id = $.jgrid.jqID(this.id), grid_p = this.p,
                newPage = grid_p.page;

            // reset the value of processing option to true to
            // skip the ajax request to 'clientArray'.
            options.processing = true;

            // delete the row
            if (grid_p.treeGrid) {
                $this.jqGrid("delTreeNode", rowid);
            } else {
                $this.jqGrid("delRowData", rowid);
            }
            $.jgrid.hideModal("#delmod" + grid_id, {
                gb: "#gbox_" + grid_id,
                jqm: options.jqModal,
                onClose: options.onClose
            });

            if (grid_p.lastpage > 1) {// on the multipage grid reload the grid
                if (grid_p.reccount === 0 && newPage === grid_p.lastpage) {
                    // if after deliting there are no rows on the current page
                    // which is the last page of the grid
                    newPage--; // go to the previous page
                }
                // reload grid to make the row from the next page visable.
                $this.trigger("reloadGrid", [{page: newPage}]);
            }

            return true;
        },
        processing: true
    },
    initDateEdit = function (elem) {
        setTimeout(function () {
            $(elem).datepicker({
                dateFormat: 'dd-M-yy',
                //autoSize: true,
                showOn: 'button',
                changeYear: true,
                changeMonth: true,
                showButtonPanel: true,
                showWeek: true
            });
        }, 100);
    },
    initDateSearch = function (elem) {
        setTimeout(function () {
            $(elem).datepicker({
                dateFormat: 'dd-M-yy',
                //autoSize: true,
                //showOn: 'button', // it dosn't work in searching dialog
                changeYear: true,
                changeMonth: true,
                showButtonPanel: true,
                showWeek: true
            });
        }, 100);
    };

grid.jqGrid({
    datatype: 'local',
    data: mydata,
    colNames: [/*'Inv No', */'Client', 'Date', 'Amount', 'Tax', 'Total', 'Closed', 'Shipped via', 'Notes'],
    colModel: [
        //{name: 'id', width: 70, align: 'center', sorttype: 'int', searchoptions: {sopt: ['eq', 'ne']}},
        {name: 'name', index: 'name', editable: true, width: 60, editrules: {required: true}},
        {name: 'invdate', index: 'invdate', width: 80, align: 'center', sorttype: 'date',
            formatter: 'date', formatoptions: {newformat: 'd-M-Y'}, editable: true, datefmt: 'd-M-Y',
            editoptions: {dataInit: initDateEdit, size: 14},
            searchoptions: {dataInit: initDateSearch}},
        {name: 'amount', index: 'amount', width: 70, formatter: 'number', editable: true, align: 'right'},
        {name: 'tax', index: 'tax', width: 50, formatter: 'number', editable: true, align: 'right'},
        {name: 'total', index: 'total', width: 60, formatter: 'number', editable: true, align: 'right'},
        {name: 'closed', index: 'closed', width: 70, align: 'center', editable: true, formatter: 'checkbox',
            edittype: 'checkbox', editoptions: {value: 'Yes:No', defaultValue: 'Yes'},
            stype: 'select', searchoptions: {sopt: ['eq', 'ne'], value: ':All;true:Yes;false:No'}},
        {name: 'ship_via', index: 'ship_via', width: 100, align: 'center', editable: true, formatter: 'select',
            edittype: 'select', editoptions: {value: 'FE:FedEx;TN:TNT;IN:Intim', defaultValue: 'Intime'},
            stype: 'select', searchoptions: {value: ':All;FE:FedEx;TN:TNT;IN:Intim'}},
        {name: 'note', index: 'note', width: 60, sortable: false, editable: true, edittype: 'textarea'}
    ],
    rowNum: 10,
    rowList: [5, 10, 20],
    pager: '#pager',
    gridview: true,
    rownumbers: true,
    autoencode: true,
    ignoreCase: true,
    sortname: 'invdate',
    viewrecords: true,
    sortorder: 'desc',
    caption: 'How to implement local form editing',
    height: '100%',
    editurl: 'clientArray',
    ondblClickRow: function (rowid, ri, ci) {
        var $this = $(this), p = this.p;
        if (p.selrow !== rowid) {
            // prevent the row from be unselected on double-click
            // the implementation is for "multiselect:false" which we use,
            // but one can easy modify the code for "multiselect:true"
            $this.jqGrid('setSelection', rowid);
        }
        $this.jqGrid('editGridRow', rowid, editSettings);
    },
    onSelectRow: function (id) {
        if (id && id !== lastSel) {
            // cancel editing of the previous selected row if it was in editing state.
            // jqGrid hold intern savedRow array inside of jqGrid object,
            // so it is safe to call restoreRow method with any id parameter
            // if jqGrid not in editing state
            if (typeof lastSel !== "undefined") {
                $(this).jqGrid('restoreRow', lastSel);
            }
            lastSel = id;
        }
    }
}).jqGrid('navGrid', '#pager', {}, editSettings, addSettings, delSettings,
    {multipleSearch: true, overlay: false,
        onClose: function (form) {
            // if we close the search dialog during the datapicker are opened
            // the datepicker will stay opened. To fix this we have to hide
            // the div used by datepicker
            $("div#ui-datepicker-div.ui-datepicker").hide();
        }});

P.S. I don't tested the code with TreeGrid, but I hope it should work too. Probably one will need to make the same call of $.unformat.date on the columns with "date" formatter too.

it works perfectly, thanks a lot. A little modification for delete: if (grid_p.treeGrid === true) { $this.jqGrid("delTreeNode", rowid); }else{ $this.jqGrid("delRowData", rowid); }

@FeKuLa: I agree, thanks! I modified the code in the demo and in the answer. By the way you can "accept" the answer to close the question.

jquery - Local form editing demo and jqGrid 4.4.1 - Stack Overflow

jquery jqgrid treegrid
Rectangle 27 1

%variables% are expanded before executing the line, so %errorlevel% will expand to some old value. (The fact that the code after && executes at all is your clue that the command returned 0)

%errorlevel%
IF errorlevel 1 ...
setlocal ENABLEDELAYEDEXPANSION
!errorlevel!

Edit: I guess tasklist is buggy and/or stupid when it comes to exit codes, I wrote some code that does not use the exit code at all:

@echo off
if "%~1"=="SOTEST" (
    start calc
    ping -n 2 localhost >nul
    for /F "tokens=1,2 skip=3" %%A in ('tasklist /FI "IMAGENAME eq calc.exe"') do (
        call "%~0" %%A %%B
    )
    call "%~0" dummy.exe 666
    goto :EOF
)
goto main


:IsTaskRunning
setlocal ENABLEEXTENSIONS&set _r=0
>nul 2>&1 (for /F "tokens=1,2" %%A in ('tasklist /FO LIST %*') do (
    if /I "%%~A"=="PID:" set _r=1
))
endlocal&set IsTaskRunning=%_r%&goto :EOF

:main
call :IsTaskRunning /FI "USERNAME eq %USERDOMAIN%\%USERNAME%" /FI "IMAGENAME eq %1" /FI "PID eq %2"
if %IsTaskRunning% gtr 0 (echo.%1:%2 is running) else (echo.%1:%2 is NOT running)

Run it as test.cmd SOTEST and it prints:

calc.exe:4852 is running
dummy.exe:666 is NOT running

But: IF errorlevel 1 is true, if the errorlevel is 1 or greater 1, this could be unexpected behaviour, I prefer IF %errorlevel% EQU 1 or IF %errorlevel% GTR 1

Hi Anders,I am already using setlocal ENABLEDELAYEDEXPANSION in my batch script and accessing the params the same way you described. But it didnt work.

@user613114: Just setting ENABLEDELAYEDEXPANSION is not enough, are you using !errorlevel! and not %errorlevel%?

But even !errorlevel! doesn't work, as errorlevel only gets 1, if the parameter format is wrong

Exit status of tasklist in batch file? - Stack Overflow

file batch-file exit status tasklist