1. #1
    Sencha Premium Member
    Join Date
    Mar 2013
    Posts
    33
    Answers
    4
    Vote Rating
    0
    BKrones is on a distinguished road

      0  

    Default Unanswered: Get changed records only by database

    Unanswered: Get changed records only by database


    Hey guys,
    i have a record and displayed by a list in Sencha Touch for example. I need to get the records which have been changed by another client. So new and changed records are loaded from database.
    I am reloading the store, but getUpdatedRecords doesn't work. I guess it's because it loads every single record again, so only
    getNewRecords returns ALL records.

    How do i autoload it, if changes at the database happened and how do i get the changed records
    and changed records by the actual client?

    What is the difference between getUpdatedRecords and getModifiedRecords? Both don't work in this case.
    Usign LocalStorage to compare current storage with new loaded storage form database?

    Best Regards,
    BKrones

  2. #2
    Sencha Premium Member
    Join Date
    Mar 2013
    Location
    England
    Posts
    52
    Answers
    2
    Vote Rating
    4
    interneers is on a distinguished road

      0  

    Post My simple thoughts..

    My simple thoughts..


    Hi,

    I believe the getUpdatedRecords() only refers to records your app updates in the store, not the datasource you originally loaded from.

    Returns all Model instances that have been updated in the Store but not yet synchronized with the Proxy.

    So it looks like you need to figure out how to synchronize with the proxy! And maybe run regular reloads of the store from the datasource to capture changes.

    Sorry I cant help more still trying to sort out the Google Chrome 29 issue in Architect, aka the cdn files which are automatically added on app creation. Havent got round to compiling my own css files yet

    Regards,

    Jacko

    Edit:

    Found a blog post that referred to offline storage, but the last part covers update after reconnection and provides 3 frameworks that may suit, not looked yet myself.

    http://www.sencha.com/blog/offline-t...-sencha-touch/

  3. #3
    Sencha Premium Member
    Join Date
    Mar 2013
    Posts
    33
    Answers
    4
    Vote Rating
    0
    BKrones is on a distinguished road

      0  

    Default


    I don't have any idea how to use those offline technologies. Anyway offline-data seems to be oversized for just comparing new data values with previous loaded records, doesn't it?

    Does anyone have an code example for using a localstorage comparing with database values and receiving new and updated ones?

    Is it possible to send an asynchronous request to server getting new record set and comparing with old one? Does anyone know how to solve it?

    Thanks alot

  4. #4
    Sencha Premium Member
    Join Date
    Mar 2013
    Location
    England
    Posts
    52
    Answers
    2
    Vote Rating
    4
    interneers is on a distinguished road

      0  

    Smile Offline blog but not the links...

    Offline blog but not the links...


    Hi,

    Just looked at WebSqlSync, and the selling point is:

    'Automatically synchronize a local WebSql database (SQLite of the browser) with a server'

    If you are using WebSql, not sure if it works with localstorage, I guess you would need to figure out how to update the store once the syncNow() function has been called.

    Regards,

    Jacko

  5. #5
    Sencha Premium Member
    Join Date
    Mar 2013
    Posts
    33
    Answers
    4
    Vote Rating
    0
    BKrones is on a distinguished road

      0  

    Default


    Hi,
    WebSQL is a good suggestion, but kind of being oversized for this request, i think.
    isn't it possible to reload teh record asynchronously without loading the complete page and using an jsonstorewriter to compare previous loaded records with new loaded records by database?

    I want to keep it as simple as possible.
    Thanks alot for your help.

    I found this example using 2 proxys:
    https://github.com/SwarmOnline/Ext.ux.OfflineSyncStore/blob/master/examples/MVC/app/view/PersonList.js

    I
    am not able to get 2 proxys using 1 store in my Sencha Architect, so is it possible to get 2 stores using Rest and Localstorage? Rest will get new values, while comparing local store. Is there are way to realise that?

  6. #6
    Sencha Premium Member
    Join Date
    Mar 2013
    Posts
    33
    Answers
    4
    Vote Rating
    0
    BKrones is on a distinguished road

      0  

    Default


    Hi guys,
    i am still on this problem, but now i got more information.
    I am using a simple list with the pullRefreshPlugin:
    Code:
    items: [            {
                    xtype: 'list',
                    title: 'People',
                    id: 'personList',
                    itemTpl: [
                        '<div>{PersonID}: {FirstName} {LastName} ({Email})</div>'
                    ],
                    store: 'PersonRestStore',
                    plugins: [
                        {
                            lastUpdatedDateFormat: 'd.m.Y H:i',
                            lastUpdatedText: 'Zuletzt aktualisiert:',
                            loadedText: 'Geladen.',
                            loadingText: 'Lädt ...',
                            pullRefreshText: 'Zum Aktualisieren herunterziehen',
                            releaseRefreshText: 'Zum Erneuern loslassen ...',
                            type: 'pullrefresh'
                        }
                    ]
                }
            ]
    2 Stores:
    JSon Store with Rest Proxy:
    Code:
    Ext.define('TicketTracker.store.PersonRestStore', {    extend: 'Ext.data.Store',
    
    
        requires: [
            'TicketTracker.model.Person'
        ],
    
    
        config: {
            autoLoad: true,
            autoSync: true,
            model: 'TicketTracker.model.Person',
            storeId: 'PersonRestStore',
            proxy: {
                type: 'rest',
                url: '/person/api/persons'
            }
        }
    });
    Json Store with LocalStorage:
    Code:
    Ext.define('TicketTracker.store.PersonLocalStore', {    extend: 'Ext.data.Store',
    
    
        requires: [
            'TicketTracker.model.Person'
        ],
    
    
        config: {
            model: 'TicketTracker.model.Person',
            storeId: 'PersonLocalStore',
            proxy: {
                type: 'localstorage'
            }
        }
    });
    The Person model:
    Code:
    Ext.define('TicketTracker.model.Person', {    extend: 'Ext.data.Model',
    
    
        config: {
            idProperty: 'PersonID',
            fields: [
                {
                    name: 'PersonID',
                    type: 'int'
                },
                {
                    name: 'FirstName',
                    type: 'string'
                },
                {
                    name: 'LastName',
                    type: 'string'
                },
                {
                    name: 'Email',
                    type: 'string'
                }
            ]
        }
    });
    Now there are 2 issues:
    1. How do i compare localstorage with new loaded records and add animation to updated records?
    I found this website: https://github.com/p5hema2/Sencha-PullRefresh-RefreshFn but i don't know how to add RefreshFn in Sencha Architect. Any ideas?
    2. It doesn't update current records if i've changed values in database before.


    EDIT:

    How do i use same functions as the PullRefresh-Plugin? Because here the plugin uses the "read" of the proxy, uses store.on and compares current and new store. I just could add an event ( no idea which one) using those methods, but i don't know how to implement them:

    Code:
    /** * This plugin adds pull to refresh functionality to the List.
     *
     * ## Example
     *
     *     @example
     *     var store = Ext.create('Ext.data.Store', {
     *         fields: ['name', 'img', 'text'],
     *         data: [
     *             {
     *                 name: 'rdougan',
     *                 img: 'http://a0.twimg.com/profile_images/1261180556/171265_10150129602722922_727937921_7778997_8387690_o_reasonably_small.jpg',
     *                 text: 'JavaScript development'
     *             }
     *         ]
     *     });
     *
     *     Ext.create('Ext.dataview.List', {
     *         fullscreen: true,
     *
     *         store: store,
     *
     *         plugins: [
     *             {
     *                 xclass: 'Ext.plugin.PullRefresh',
     *                 pullRefreshText: 'Pull down for more new Tweets!'
     *             }
     *         ],
     *
     *         itemTpl: [
     *             '<img src="{img}" alt="{name} photo" />',
     *             '<div class="tweet"><b>{name}:</b> {text}</div>'
     *         ]
     *     });
     */
    Ext.define('Ext.plugin.PullRefresh', {
        extend: 'Ext.Component',
        alias: 'plugin.pullrefresh',
        requires: ['Ext.DateExtras'],
    
    
        config: {
            /**
             * @cfg {Ext.dataview.List} list
             * The list to which this PullRefresh plugin is connected.
             * This will usually by set automatically when configuring the list with this plugin.
             * @accessor
             */
            list: null,
    
    
            /**
             * @cfg {String} pullRefreshText The text that will be shown while you are pulling down.
             * @accessor
             */
            pullRefreshText: 'Pull down to refresh...',
    
    
            /**
             * @cfg {String} releaseRefreshText The text that will be shown after you have pulled down enough to show the release message.
             * @accessor
             */
            releaseRefreshText: 'Release to refresh...',
    
    
            /**
             * @cfg {String} lastUpdatedText The text to be shown in front of the last updated time.
             * @accessor
             */
            lastUpdatedText: 'Last Updated:',
    
    
            /**
             * @cfg {String} lastUpdatedDateFormat The format to be used on the last updated date.
             */
            lastUpdatedDateFormat: 'm/d/Y h:iA',
    
    
            /**
             * @cfg {String} loadingText The text that will be shown while the list is refreshing.
             * @accessor
             */
            loadingText: 'Loading...',
    
    
            /**
             * @cfg {String} loadedText The text that will be when data has been loaded.
             * @accessor
             */
            loadedText: 'Loaded.',
    
    
            /**
             * @cfg {Boolean} autoSnapBack Determines whether the pulldown should automatically snap back after data has been loaded.
             * If false call {@link #snapBack}() to manually snap the pulldown back.
             */
            autoSnapBack: true,
            /**
             * @cfg {Number} snappingAnimationDuration The duration for snapping back animation after the data has been refreshed
             * @accessor
             */
            snappingAnimationDuration: 300,
    
    
            /**
             * @cfg {Number} overpullSnapBackDuration The duration for snapping back when pulldown has been lowered further then its height.
             */
            overpullSnapBackDuration: 300,
    
    
            /**
             * @cfg {Ext.XTemplate/String/Array} pullTpl The template being used for the pull to refresh markup.
             * @accessor
             * @private
             */
            pullTpl: [
                '<div class="x-list-pullrefresh">',
                    '<div class="x-list-pullrefresh-arrow"></div>',
                    '<div class="x-loading-spinner">',
                        '<span class="x-loading-top"></span>',
                        '<span class="x-loading-right"></span>',
                        '<span class="x-loading-bottom"></span>',
                        '<span class="x-loading-left"></span>',
                    '</div>',
                    '<div class="x-list-pullrefresh-wrap">',
                        '<h3 class="x-list-pullrefresh-message"></h3>',
                        '<div class="x-list-pullrefresh-updated"></div>',
                    '</div>',
                '</div>'
            ].join(''),
    
    
            translatable: true
        },
    
    
        /**
         * @event latestfetched
         * Fires when the latest data has been fetched
         */
    
    
        isRefreshing: false,
        currentViewState: '',
    
    
        initialize: function() {
            this.callParent();
    
    
            this.on({
                painted: 'onPainted',
                scope: this
            });
        },
    
    
        init: function(list) {
            var me = this;
    
    
            me.setList(list);
            me.initScrollable();
        },
    
    
        initScrollable: function() {
            var me = this,
                list = me.getList(),
                store = list.getStore(),
                pullTpl = me.getPullTpl(),
                element = me.element,
                scrollable = list.getScrollable(),
                scroller;
    
    
            if (!scrollable) {
                return;
            }
    
    
            scroller = scrollable.getScroller();
            scroller.setAutoRefresh(false);
    
    
            me.lastUpdated = new Date();
    
    
            list.insert(0, me);
    
    
            // We provide our own load mask so if the Store is autoLoading already disable the List's mask straight away,
            // otherwise if the Store loads later allow the mask to show once then remove it thereafter
            if (store) {
                if (store.isAutoLoading()) {
                    list.setLoadingText(null);
                } else {
                    store.on({
                        load: {
                            single: true,
                            fn: function() {
                                list.setLoadingText(null);
                            }
                        }
                    });
                }
            }
    
    
            pullTpl.overwrite(element, []);
    
    
            me.loadingElement = element.getFirstChild();
            me.messageEl = element.down('.x-list-pullrefresh-message');
            me.updatedEl = element.down('.x-list-pullrefresh-updated');
    
    
            me.maxScroller = scroller.getMaxPosition();
    
    
            scroller.on({
                maxpositionchange: me.setMaxScroller,
                scroll: me.onScrollChange,
                scope: me
            });
    
    
            me.resetRefreshState();
        },
    
    
        onScrollableChange: function() {
            this.initScrollable();
        },
    
    
        updateList: function(newList, oldList) {
            var me = this;
    
    
            if (newList && newList != oldList) {
                newList.on({
                    order: 'after',
                    scrollablechange: me.onScrollableChange,
                    scope: me
                });
            } else if (oldList) {
                oldList.un({
                    order: 'after',
                    scrollablechange: me.onScrollableChange,
                    scope: me
                });
            }
        },
    
    
        /**
         * @private
         * Attempts to load the newest posts via the attached List's Store's Proxy
         */
        fetchLatest: function() {
            var store = this.getList().getStore(),
                proxy = store.getProxy(),
                operation;
    
    
            operation = Ext.create('Ext.data.Operation', {
                page: 1,
                start: 0,
                model: store.getModel(),
                limit: store.getPageSize(),
                action: 'read',
                sorters: store.getSorters(),
                filters: store.getRemoteFilter() ? store.getFilters() : []
            });
    
    
            proxy.read(operation, this.onLatestFetched, this);
        },
    
    
        /**
         * @private
         * Called after fetchLatest has finished grabbing data. Matches any returned records against what is already in the
         * Store. If there is an overlap, updates the existing records with the new data and inserts the new items at the
         * front of the Store. If there is no overlap, insert the new records anyway and record that there's a break in the
         * timeline between the new and the old records.
         */
        onLatestFetched: function(operation) {
            var store      = this.getList().getStore(),
                list       = this.getList(),
                scroller   = list.getScrollable().getScroller(),
                scrollerOffsetX = scroller.position.x,
                scrollerOffsetY = scroller.position.y,
                oldRecords = store.getData(),
                newRecords = operation.getRecords(),
                length     = newRecords.length,
                toInsert   = [],
                newRecord, oldRecord, i;
    
    
            for (i = 0; i < length; i++) {
                oldRecord = oldRecords.getByKey(newRecord.getId());
    google            newRecord = newRecords[i];
    
    
                if (oldRecord) {
                    oldRecord.set(newRecord.getData());
                } else {
                    toInsert.push(newRecord);
                }
    
    
                oldRecord = undefined;
            }
    
    
            store.insert(0, toInsert);
            scroller.scrollTo(scrollerOffsetX, scrollerOffsetY);
    
    
            this.setViewState('loaded');
            this.fireEvent('latestfetched');
            if (this.getAutoSnapBack()) {
                this.snapBack();
            }
        },
    
    
        snapBack: function() {
            var me = this,
                list = me.getList(),
                scroller = list.getScrollable().getScroller();
    
    
            scroller.on({
                scrollend: function() {
                    this.resetRefreshState();
                },
                single: true,
                scope: me
            });
    
    
            if (scroller.position.y < 0) {
                scroller.minPosition.y = 0;
                scroller.scrollTo(null, 0, {duration: scroller.isTouching ? 0 : me.getSnappingAnimationDuration()});
            }
        },
    
    
        onPainted: function() {
            this.pullHeight = this.loadingElement.getHeight();
        },
    
    
        setMaxScroller: function(scroller, position) {
            this.maxScroller = position;
        },
    
    
        onScrollChange: function(scroller, x, y) {
            if (y <= 0) {
                this.onBounceTop(y);
            }
            if (y > this.maxScroller.y) {
                this.onBounceBottom(y);
            }
        },
    
    
        /**
         * @private
         */
        applyPullTpl: function(config) {
            return (Ext.isObject(config) && config.isTemplate) ? config : new Ext.XTemplate(config);
        },
    
    
        onBounceTop: function(y) {
            var me = this,
                pullHeight = me.pullHeight,
                list = me.getList(),
                scroller = list.getScrollable().getScroller();
    
    
            if (!me.isReleased) {
                if (!pullHeight) {
                    me.onPainted();
                    pullHeight = me.pullHeight;
                }
                if (!me.isRefreshing && -y >= pullHeight + 10) {
                    me.isRefreshing = true;
    
    
                    me.setViewState('release');
    
    
                    scroller.getContainer().onBefore({
                        dragend: 'onScrollerDragEnd',
                        single: true,
                        scope: me
                    });
                }
                else if (me.isRefreshing && -y < pullHeight + 10) {
                    me.isRefreshing = false;
                    me.setViewState('pull');
                }
            }
    
    
            me.getTranslatable().translate(0, -y);
        },
    
    
        onScrollerDragEnd: function() {
            var me = this;
    
    
            if (me.isRefreshing) {
                var list = me.getList(),
                    scroller = list.getScrollable().getScroller(),
                    translateable = scroller.getTranslatable();
    
    
                translateable.setEasingY({duration:this.getOverpullSnapBackDuration()});
                scroller.minPosition.y = -me.pullHeight;
                scroller.on({
                    scrollend: 'loadStore',
                    single: true,
                    scope: me
                });
    
    
                me.isReleased = true;
            }
        },
    
    
        loadStore: function() {
            var me = this;
    
    
            me.setViewState('loading');
            me.isReleased = false;
            me.fetchLatest();
        },
    
    
        onBounceBottom: Ext.emptyFn,
    
    
        setViewState: function(state) {
            var me = this,
                prefix = Ext.baseCSSPrefix,
                messageEl = me.messageEl,
                loadingElement = me.loadingElement;
    
    
            if (state === me.currentViewState) {
                return me;
            }
            me.currentViewState = state;
    
    
            if (messageEl && loadingElement) {
                switch (state) {
                    case 'pull':
                        messageEl.setHtml(me.getPullRefreshText());
                        loadingElement.removeCls([prefix + 'list-pullrefresh-release', prefix + 'list-pullrefresh-loading']);
                    break;
    
    
                    case 'release':
                        messageEl.setHtml(me.getReleaseRefreshText());
                        loadingElement.addCls(prefix + 'list-pullrefresh-release');
                    break;
    
    
                    case 'loading':
                        messageEl.setHtml(me.getLoadingText());
                        loadingElement.addCls(prefix + 'list-pullrefresh-loading');
                    break;
    
    
                    case 'loaded':
                        messageEl.setHtml(me.getLoadedText());
                        loadingElement.addCls(prefix + 'list-pullrefresh-loaded');
                        break;
                }
            }
    
    
            return me;
        },
    
    
        resetRefreshState: function() {
            var me = this;
    
    
            me.isRefreshing = false;
            me.lastUpdated = new Date();
    
    
            me.setViewState('pull');
            me.updatedEl.setHtml(this.getLastUpdatedText() + '&nbsp;' + Ext.util.Format.date(me.lastUpdated, me.getLastUpdatedDateFormat()));
        }
    });


  7. #7
    Sencha Premium Member
    Join Date
    Mar 2013
    Posts
    33
    Answers
    4
    Vote Rating
    0
    BKrones is on a distinguished road

      0  

    Default


    Hi again,
    now i am overwriting the "PullRefreshPlugin" with this code:
    Code:
    Ext.define('TicketTracker.override.plugin.PullRefresh', {
        override: 'Ext.plugin.PullRefresh',
        onLatestFetched: function(operation) {
            var store           = this.getList().getStore(),
                oldRecords      = store.getData(),
                old_length      = oldRecords.length,
                newRecords      = operation.getRecords(),
                length          = newRecords.length,
                toInsert        = [],
                newRecordIds    = [],
                oldRecordsArr   = [],
                toRemove        = [],
                newRecord, newRecordIndex, oldRecord, i;
            console.log('--------------------------------------------------------------------------------------------------------------');
            for (i = 0; i < length; i++) {
                newRecord = newRecords[i];
                oldRecord = oldRecords.getByKey(newRecord.getId());
    	console.log('oldRecord: ' + oldRecord.get('BasePriority') + ', newRecord:' + newRecord.get('BasePriority'));
                newRecordIds.push(newRecord.getId());
                
                if (oldRecord) {
                    oldRecord.set(newRecord.getData());
                } else {
                    toInsert.push(newRecord);
                }
    
                oldRecord = undefined;
            }
    
            store.insert(0, toInsert);
            for(i = 0; i < length; i++) {
                newRecord = store.getAt(i);
                oldRecord = oldRecords.getByKey(newRecord.getId());
            }
    
            oldRecordsArr = store.getRange();
            for (i = 0; i < old_length; i++) {
                oldRecord = oldRecordsArr[i];
                newRecordIndex = newRecordIds.indexOf(oldRecord.getId());
    
                if (newRecordIndex === undefined || newRecordIndex == -1) {
                    toRemove.push(oldRecord);
                }
    
                oldRecord = undefined;
            }
            store.remove(toRemove);
        }
    });
    The red part of the code should show me new records and the old ones, but both show me the new ones. Does this refer to the 'onLastestFetched' Function/Event?

    I still need to get both, to compare them and get only the modified/updated ones.

    Thank you.

Thread Participants: 1

Tags for this Thread

Turkiyenin en sevilen filmlerinin yer aldigi xnxx internet sitemiz olan ve porn sex tarzi bir site olan mobil porno izle sitemiz gercekten dillere destan bir durumda herkesin sevdigi bir site olarak tarihe gececege benziyor. Sitenin en belirgin ozelliklerinden birisi de Turkiyede gercekten kaliteli ve muntazam, duzenli porno izle siteleri olmamasidir. Bu yuzden iste. Ayrica en net goruntu kalitesine sahip adresinde yayinlanmaktadir. Mesela diğer sitelerimizden bahsedecek olursak, en iyi hd porno video arşivine sahip bir siteyiz. "The Best anal porn videos and slut anus, big asses movies set..."