Monday, August 6, 2012

Manual model and view synchronization with JavaScript

When you don't use an MVC javascript framework that can do two-way databinding, you are left on your own to synchronize the state between the model and the view.


Live test: http://jsfiddle.net/E7F7D/33/

<table id='dataHere' border='1'>
<thead>
    <!-- ID presence on HTML is optional --> 
    <!--<th style='visibility: collapse'>Id</th>-->
    
    <th>Lastname</th><th>Firstname</th><th>Asset</th><th>Actions</th>
</thead>
<tbody>
</tbody>
    
    
</table>

<hr/>

    <input type="button" id="viaModel" value="test via model"/>

    <input type="button" id="viaDom" value="test via DOM"/>
        
    <div id="debugLog">
     </div>


<script>
    var people = [
        { Id: 1, Lastname: 'Lennon', Firstname: 'John', Asset: 40090.1296 },
        { Id: 2, Lastname: 'McCartney', Firstname: 'Paul', Asset: 38000.34 },
        { Id: 3, Lastname: 'Harrison', Firstname: 'George', Asset: 37000.56 },
        { Id: 4, Lastname: 'Starr', Firstname: 'Ringo', Asset: 40000.78 },
        
        { Id: 5, Lastname: 'Buendia', Firstname: 'Ely', Asset: 40000.93 },
        { Id: 6, Lastname: 'Marasigan', Firstname: 'Raymund', Asset: 39000.12 },
        { Id: 7, Lastname: 'Zabala', Firstname: 'Buddy', Asset: 39000.13 },
        { Id: 8, Lastname: 'Adoro', Firstname: 'Marcus', Asset: 39000.14344 }    
        
        ];
    
    
    var tbl = $('#dataHere');
    
    $('#viaModel').click(function() {
        var dl = $('#debugLog');
        dl.html('Model-based approach. Data are in their pristine state');
        $.each(people, function() {
            var person = this;
            
            dl.append(person.Id + '-->' + person.Lastname + ', ' + person.Firstname + ': ' + this.Asset + '<p/>');
        });
    });
    
    $('#viaDom').click(function() {
        try {
            var dl = $('#debugLog');
            var tbl = $('#dataHere');
    
            dl.html('Using DOM approach for stashing and extracting data, the Id won\'t be available unless we stash it on HTML');
            
            
    
            var trs = $('tbody > tr', tbl);
    
    
            $.each(trs, function() {
                var tr = this;
                var tds = $('td', tr);
        
                // Alas! ID won't be available if you didn't put it in td tag or whatnot.
                // If we use DOM approach for stashing our data, 
                // we have to stash ID on the HTML itself, 
                // this is called Smart UI approach, this is abhored, 
                // as the code is tightly coupled to UI/presentation layer.
                
        
                var tdLastname = $(tds[0]);
                var tdFirstname = $(tds[1]);                       
                var tdAsset = $(tds[2]);
                
                
                
                var lastname = tdLastname.text();
                var firstname = tdFirstname.text();
                // another problem with Smart UI approach is the data gets mangled
                
                var asset = tdAsset.text().replace('Php ','').replace(',','');
                
                dl.append(lastname + ', '+ firstname + ': ' + asset);                
                
                
            })
                
            dl.append('And data gets mangled and truncated too. Check the rounding-offs');
        
        } catch(e) {
            alert(e);
        }
                       
    });
    
    
    $.each(people, function() {
        var person = this;
        
        var trPerson = $('<tr/>');
    
        
        // optional
        // var tdId = $('<td/>').css('visibility','collapse');
        
        var tdLastname = $('<td/>');
        var tdFirstname = $('<td/>');
        var tdAsset = $('<td/>');
        var tdActions = $('<td/>');
        
        var aEditAction = $('<a/>').prop('href','#').text('Edit');
        var aDeleteAction = $('<a/>').prop('href','#').text('Delete');
        
       
        // optional
        // tdId.text(this.Id);
        
        tdLastname.text(this.Lastname);
        tdFirstname.text(this.Firstname);
        tdAsset.text(formatMoney(this.Asset, 2, 'Php ', ',','.'));
    
        
        aEditAction.click(function() {
            // alert('Will edit ' + person.Id + ' ' + person.Lastname);
            
            
            var ln = prompt('Enter value', person.Lastname);
            person.Lastname = ln == null ? person.Lastname : ln;
            
            tdLastname.text(person.Lastname);
        });        
        
     
        
        aDeleteAction.click(function() {
            if (confirm('Will delete ' + person.Id + ' ' + person.Lastname)) {   
                
                people.splice(people.indexOf(person),1);
                
                trPerson.remove();
            }
        });
        
            
    
        
        trPerson
            // .append(tdId) // optional
            .append(tdLastname).append(tdFirstname)
            .append(tdAsset).append(tdActions);
        
        tdActions.append(aEditAction).append('|').append(aDeleteAction);
    
      
          
        tbl.append(trPerson);
    
            
    });
    
     // alert(8);
        // alert(formatMoney(92334.55, 2,'Php ',',','.'));
        
    // http://www.josscrowcroft.com/2011/code/format-unformat-money-currency-javascript/
    function formatMoney(number, places, symbol, thousand, decimal) {
        number = number || 0;
        places = !isNaN(places = Math.abs(places)) ? places : 2;
        symbol = symbol !== undefined ? symbol : "$";
        thousand = thousand || ",";
        decimal = decimal || ".";
        var negative = number < 0 ? "-" : "",
            i = parseInt(number = Math.abs(+number || 0).toFixed(places), 10) + "",
            j = (j = i.length) > 3 ? j % 3 : 0;
        return symbol + negative + (j ? i.substr(0, j) + thousand : "") + i.substr(j).replace(/(\d{3})(?=\d)/g, "$1" + thousand) + (places ? decimal + Math.abs(number - i).toFixed(places).slice(2) : "");
    }
</script>

No comments:

Post a Comment