21 Nisan 2013 Pazar

Windows 8 JavaScript Veri Bağlama

Yorum Bırak

     Merhaba arkadaşlar, geçen hafta sizlere Windows 8 JavaScript uygulamalarında 'promise' kullanımından bahsetmiştim. Bu hafta da sizlere Javascript ile veri bağlama konusundan bahsedeceğim.

     Bunun için Visual Studio'dan yeni bir Windows 8 JavaScript projesi açıyoruz. Açtığımız proje içersine html diye bir klasör ekliyoruz. İçerisine iki adet html dosyası ekliyoruz, birinin adını "_BasicBinding.html"
ve diğerinin adını da "_TemplateControl.html" olarak değiştiriyoruz.
İçerisine de iki adet JavaScript dosyası ekliyoruz. Birinin ismini "_BasicBinding.js" olarak değiştiriyoruz ve diğer JavaScript dosyamızın ismini de "_TemplateControl.js" olarak düzenliyoruz.

     '_BasicBinding.html' dosyasını aşağıdaki gibi düzenliyoruz:




 <!DOCTYPE html>   
 <html xmlns="http://www.w3.org/1999/xhtml">   
 <head>   
   <title></title>   
   <link rel="stylesheet" href="/css/1_BasicBinding.css" />   
   <script src="/js/1_BasicBinding.js"></script>   
 </head>   
 <body>   
   <div data-win-control="SdkSample.ScenarioInput">   
   <p>   
    This is an example of basic declarative data binding. The output below uses data   
    binding expressions to connect the DOM display to elements of the data object. Change   
    the fields here to see the destination DOM elements update via binding.</p>   
   <div id="basicBindingInputs">   
    <ol id="basicBindingTextInputList">   
     <li>   
      <label for="basicBindingInputText">   
       Text:</label>   
      <input type="text" id="basicBindingInputText" />   
     </li>   
    </ol>   
    <ol id="basicBindingColorInputList">   
     <li>   
      <label for="basicBindingInputRed">   
       Red:</label>   
      <input type="text" id="basicBindingInputRed" />   
     </li>   
     <li>   
      <label for="basicBindingInputGreen">   
       Green:</label>   
      <input type="text" id="basicBindingInputGreen" />   
     </li>   
     <li>   
      <label for="basicBindingInputBlue">   
       Blue:</label>   
      <input type="text" id="basicBindingInputBlue" />   
     </li>   
    </ol>   
   </div>  </div>   
   <div data-win-control="SdkSample.ScenarioOutput">   
   <p>   
    This text is bound to the inputs above via data binding attributes.</p>   
   <div id="basicBindingOutput">   
    <p>   
     The text you entered was   
     <!-- the most basic binding expression - simple assignment from a destination -->   
     <span data-win-bind="innerHTML: text"></span>. The value for red is   
     <!-- More complex - you can use dot notation to get at properties of child object on the data source -->   
     <span data-win-bind="innerHTML: color.red"></span>,   
     <!-- Just like JavaScript, square brackets work for property access as well -->   
     the value for green is <span data-win-bind="innerHTML: color['green']"></span>, and blue   
    is <span data-win-bind="innerHTML: color.blue"></span>.   
    </p>   
    <!-- This binding shows that dot notation works for the destination property as well, and   
     demonstrates using a binding initializer - the BasicBinding.toCssColor function will be called   
     as part of setting up this binding. -->   
    <p data-win-bind="style.background: color BasicBinding.toCssColor">   
     And here's your color as a background.</p>   
   </div>  </div>   
 </body>   
 </html>   

    Bu sayafada 3 adet text input koyduk ve bunları diğer JavaScript dosyalarımızla bağladık. Bu inputların içerisine girdiğimiz sayılara göre sayfalarda kullandığımız diğer kontrollerin renkleri JavaScript tarafından bağlanarak ayarlanıyor. Sayfanın son hali aşağıdaki gibidir:


    ' _TemplateControl.html'     de aşağıdaki gibi değiştiriyoruz:

 <html xmlns="http://www.w3.org/1999/xhtml">   
 <head>   
   <title></title>   
   <link rel="stylesheet" href="/css/2_TemplateControl.css" />   
   <script src="/js/2_TemplateControl.js"></script>   
 </head>   
 <body>   
   <div data-win-control="SdkSample.ScenarioInput">   
     <p>   
       If you're rendering the same user interface multiple times with   
       different data, then a great way to do this is use a template   
       control. WinJS Binding Templates let you specify the UI and   
       binding once, then render the template itself multiple times.   
       This example renders the template control three times, bound   
       to different data. Change the data and you'll see the bindings   
       fire to update the individual items that were rendered from the   
       template.   
     </p>   
     <p>The aria-label attribute is also being set as part of data binding.   
       Turn on Windows Narrator (using Win-Enter) and click on the rendered   
       templates to have the screen reader read the bound label.   
     </p>   
     <fieldset id="templateControlObject">   
       <legend>Object to edit</legend>   
       <select id="templateControlObjectSelector">   
         <option value="0">Object 1</option>   
         <option value="1">Object 2</option>   
         <option value="2">Object 3</option>   
       </select>   
     </fieldset>   
     <fieldset id="templateControlInputText">   
       <legend>Text</legend>   
       <input type="text" id="templateControlInputTextInput" />   
     </fieldset>   
     <fieldset id="templateControlInputColor">   
       <legend>Color</legend>   
       <ol>   
         <li>   
           <label for="templateControlInputRed">   
             Red:   
           </label>   
           <input type="text" id="templateControlInputRed" />   
         </li>   
         <li>   
           <label for="templateControlInputGreen">   
             Green:   
           </label>   
           <input type="text" id="templateControlInputGreen" />   
         </li>   
         <li>   
           <label for="templateControlInputBlue">   
             Blue:   
           </label>   
           <input type="text" id="templateControlInputBlue" />   
         </li>   
       </ol>   
     </fieldset>   
     <!--   
     This is our template control. You'll notice it is not rendered in the UI. Template controls are removed from the DOM   
     when processed in order to prevent them getting hit via CSS selectors or other DOM searches.   
     -->   
     <div id="templateControlTemplate" data-win-control="WinJS.Binding.Template">   
       <!-- Bind both the background and the aria-label HTML attribute for the div -->   
       <div class="templateControlRenderedItem"   
         data-win-bind="style.background: color TemplateControl.toCssColor;   
         this['aria-label']: text WinJS.Binding.setAttribute" role="article">   
         <ol>   
           <li data-win-bind="textContent: text"></li>   
           <li><span class="templateControlTemplateLabel">r: </span><span data-win-bind="textContent: color.r"></span></li>   
           <li><span class="templateControlTemplateLabel">g: </span><span data-win-bind="textContent: color.g"></span></li>   
           <li><span class="templateControlTemplateLabel">b: </span><span data-win-bind="textContent: color.b"></span></li>   
         </ol>   
       </div>   
     </div>   
   </div>   
   <div data-win-control="SdkSample.ScenarioOutput">   
     <div id="templateControlRenderTarget">   
     </div>   
   </div>   
 </body>   
 </html>   

       Bu sayfanın görüntüsü de aşağıdaki gibidir:


     Bu kısımda inputların içerisine girdiğimiz değerler aşağıdaki kare kutuların arka plan rengini değiştirmek için JavaScript kodları tarafından bağlanıyor ve yazı olarak da yine aynı şekilde JavaScript kodlarımız tarafından bağlanıyor.

          '_BasicBinding.js' JavaScript uygulamasını da aşağıdaki gibi düzenliyoruz:

 (function () {   
   "use strict";   
   var page = WinJS.UI.Pages.define("/html/1_BasicBinding.html", {   
     init: function (element, options) {   
       // Our data source - not that this is not explicitly   
       // bindable - that's done later.   
       this.bindingSource = {   
         text: "Initial text",   
         color: {   
           red: 128,   
           green: 128,   
           blue: 128   
         }   
       };   
     },   
     ready: function (element, options) {   
       // Hook up our inputs so that they update the   
       // appropriate places in our binding source.   
       // First, we call WinJS.Binding.as to get the bindable proxy object   
       var b = WinJS.Binding.as(this.bindingSource);   
       // The bindTextBox method wired up change events, defined below   
       this.bindTextBox("#basicBindingInputText", b.text,   
         function (value) { b.text = toStaticHTML(value); });   
       this.bindTextBox("#basicBindingInputRed", b.color.red,   
         function (value) { b.color.red = toStaticHTML(value); });   
       this.bindTextBox("#basicBindingInputGreen", b.color.green,   
         function (value) { b.color.green = toStaticHTML(value); });   
       this.bindTextBox("#basicBindingInputBlue", b.color.blue,   
         function (value) { b.color.blue = toStaticHTML(value); });   
       // Now, hook up the declarative binding to our binding source.   
       // This is done via a call to WinJS.Binding.processAll, passing the   
       // target element and the binding source.   
       WinJS.Binding.processAll(element.querySelector("#basicBindingOutput"), this.bindingSource)   
         .done(function () {   
           // processAll is async. You can hook up a then or done handler   
           // if you need to wait for the binding to finish   
           WinJS.log && WinJS.log("Binding wireup complete", "sample", "status");   
         });   
     },   
     //   
     // Helper function to set up bindings on text boxes   
     //   
     bindTextBox: function (selector, initialValue, setterCallback) {   
       var textBox = this.element.querySelector(selector);   
       textBox.addEventListener("change", function (evt) {   
         setterCallback(evt.target.value);   
       }, false);   
       textBox.value = initialValue;   
     }   
   });   
   // Custom binding initializer to convert to CSS color   
   // This method is called to set up the binding. It only gets called once.   
   // Source is the source object, sourceProperty is the strings   
   // supplied in the binding action, dest is the destination object,   
   // and destProperty is the destination property string.   
   //   
   // Note the function is wrapped in a call to WinJS.Binding.initializer.   
   // This marks this function as usable in declarative markup.   
   var toCssColor = WinJS.Binding.initializer(   
     function toCssColor(source, sourceProperty, dest, destProperty) {   
       // in this case, we're binding to a composite property. In order   
       // to get things to fire properly, we're going to hook up   
       // to multiple fields in the source object.   
       // helper method to actually set the style   
       function setBackColor() {   
         dest.style.backgroundColor = rgb(source.color.red, source.color.green, source.color.blue);   
       }   
       // in this case, we're binding to a composite property. In order   
       // to get things to fire properly, we're going to hook up   
       // to multiple fields in the source object.   
       // Make sure to return the result of calling bind - this allows the   
       // binding system to properly clean up if the target element gets   
       // removed from the DOM.   
       return WinJS.Binding.bind(source, {   
         color: {   
           red: setBackColor,   
           green: setBackColor,   
           blue: setBackColor,   
         }   
       });   
     }   
   );   
   // A little helper function to convert from separate rgb values to a css color   
   function rgb(r, g, b) { return "rgb(" + [r, g, b].join(",") + ")"; }   
   // Binding initializers must be available as a public reference   
   // in order to be used declaratively. "Publish" our binding   
   // initializer via a namespace   
   WinJS.Namespace.define("BasicBinding", {   
     toCssColor: toCssColor   
   });   
 })();   

     Bu JavaScript dosyasında da input textlerin varsayılan yazılarını belirledik ve 'bindTextBox' adlı fonksiyon ile de bunların içersindeki değerler değiştirildiğinde olacakları belirledik. 'toCssColor' fonksiyonu ile de bu sayfa ile alakalı olan html dosyası içersindeki arka plan rengini değiştirdiğimiz kısımın renk bağlama olayını sağlamış olduk. Bu kısımda rgb renk kodlarından da faydalandık çünkü zaten bizim inputlara girdiğimiz sayılar bu rgb renk kodlarının değerleri. Bu üç renk değerine göre bir renk oluşuyor ve ona göre de arka plan rengi değiştiriliyor.
     '_TemplateControl.js' dosyasını da aşağıdaki gibi düzenliyoruz:

 (function () {   
   "use strict";   
   // We want a bunch of these objects, so we're using   
   // WinJS.Binding.define to declare an observable type.   
   var DataSource = WinJS.Binding.define({   
     text: "",   
     color: { r: 0, g: 0, b: 0 }   
   });   
   var page = WinJS.UI.Pages.define("/html/2_TemplateControl.html", {   
     init: function (element, options) {   
       // Our actual data - we don't need to use WinJS.Binding.as on these   
       // objects as they're already observable (since they were created by   
       // WinJS.Binding.define).   
       this.sourceObjects = [   
         // This creates the observable object defined above and initializes its properties   
         // from the data object passed in.   
         new DataSource({ text: "First object", color: { r: 192, g: 64, b: 64 } }),   
         new DataSource({ text: "Second object", color: { r: 64, g: 192, b: 64 } }),   
         new DataSource({ text: "Third object", color: { r: 51, g: 153, b: 255 } })   
       ];   
     },   
     ready: function (element, options) {   
       var prefix = "#templateControlInput";   
       this.textBox = element.querySelector(prefix + "TextInput");   
       this.redTextBox = element.querySelector(prefix + "Red");   
       this.greenTextBox = element.querySelector(prefix + "Green");   
       this.blueTextBox = element.querySelector(prefix + "Blue");   
       element.querySelector("#templateControlObjectSelector")   
         .addEventListener("change", this.sourceObjectChange.bind(this), false);   
       // The data source the UI is currently manipulating   
       this.dataSource = this.sourceObjects[0];   
       // Hook up the input events   
       this.bindInputs();   
       //   
       // Render our template controls into the output DIV   
       //   
       var templateControl = element.querySelector("#templateControlTemplate").winControl;   
       // The div to render into   
       var renderHere = element.querySelector("#templateControlRenderTarget");   
       this.sourceObjects.forEach(function (o) {   
         templateControl.render(o, renderHere);   
       });   
     },   
     bindInputs: function () {   
       // Hook up event handlers for changes in the UI   
       var that = this;   
       this.textBox.addEventListener("change", function (evt) {   
         that.dataSource.text = toStaticHTML(that.textBox.value);   
       }, false);   
       that.redTextBox.addEventListener("change", function () {   
         that.dataSource.color.r = toStaticHTML(that.redTextBox.value);   
       }, false);   
       that.greenTextBox.addEventListener("change", function () {   
         that.dataSource.color.g = toStaticHTML(that.greenTextBox.value);   
       }, false);   
       that.blueTextBox.addEventListener("change", function () {   
         that.dataSource.color.b = toStaticHTML(that.blueTextBox.value);   
       }, false);   
       this.updateInputs();   
     },   
     updateInputs: function () {   
       // Update the UI to match the contents of seleted data source.   
       this.textBox.value = this.dataSource.text;   
       this.redTextBox.value = this.dataSource.color.r;   
       this.greenTextBox.value = this.dataSource.color.g;   
       this.blueTextBox.value = this.dataSource.color.b;   
     },   
     // Event handler that triggers when the "object to change"   
     // dropdown changes.   
     sourceObjectChange: function (eventObject) {   
       this.dataSource = this.sourceObjects[eventObject.target.selectedIndex];   
       this.updateInputs();   
     }   
   });   
   //   
   // A binding initializer used to convert separate r,g,b properties   
   // of an object to a single css color definition   
   //   
   // Note the function is wrapped in a call to WinJS.Binding.initializer.   
   // This marks this function as usable in declarative markup.   
   var toCssColor = WinJS.Binding.initializer(   
     function toCssColor(source, sourceProperty, dest, destProperty) {   
       // in this case, we're binding to a composite property. In order   
       // to get things to fire properly, we're going to hook up   
       // to multiple fields in the source object.   
       // helper method to actually set the style   
       function setBackColor() {   
         dest.style.backgroundColor = rgb(source.color.r, source.color.g, source.color.b);   
       }   
       // helper function to convert to css style rgb syntax   
       function rgb(r, g, b) {   
         return "rgb(" + r + "," + g + "," + b + ")";   
       }   
       // in this case, we're binding to a composite property. In order   
       // to get things to fire properly, we're going to hook up   
       // to multiple fields in the source object.   
       // Make sure to return the result of calling bind - this allows the   
       // binding system to properly clean up if the target element gets   
       // removed from the DOM.   
       return WinJS.Binding.bind(source, {   
         color: {   
           r: setBackColor,   
           g: setBackColor,   
           b: setBackColor,   
         }   
       });   
     }   
   );   
   //   
   // Binding initializers have to be public, so publish this out   
   // via a namespace   
   //   
   WinJS.Namespace.define("TemplateControl", {   
     toCssColor: toCssColor   
   });   
 })();   

     Bu kısımda da gene aynı şekilde arka plan rengini ve inputların içerisindeki yazıları bağlamak için methodlar kullandık ve değerler değiştirildiğinde gerekli bağlama işlemleri buradan yapıldı.

     Veri bağlama derken JavaScript ile veri tabanına falan bağlanmadık. Burada amaç programın çalışması sırasında bazı bilgilerin html tarafındaki değişiklikleri etkileyecek şekilde bağlanmasıydı. Biraz daha açıklayıcı olursak burada JavaScript ile bazı kontrollerin arka plan rengini programın çalışması sırasında yaptığımız dinamik değişiklikler ile sağlamış olduk.

     Şimdi de sizlere ListView'e nasıl veri bağlayabiliriz onunla ilgili bir örnek anlatacağım. Bunun için önce JavaScript dosyamızı paylaşalım ve daha sonra kodumuzu açıklayalım. JavaScript dosyamız aşağıdaki gibi olacak:


 (function () {  
 'use strict';  
 // Uncomment the following line to enable first chance exceptions.  
 // Debug.enableFirstChanceException(true);  
 var PlayerData = [  
 { Name: 'Sachin Tendulkar', Photo: 'images/ST.jpg' },  
 { Name: 'Mahender Singh Dhoni', Photo: 'images/MSD.jpg' },  
 { Name: 'Saurabh Ganguli', Photo: 'images/SG.jpg' },  
 { Name: 'Harbhajan Singh', Photo: 'images/HS.jpg' },  
 { Name: 'Youvrah Singh', Photo: 'images/YS.jpg' },  
 { Name: 'VVS Laxman', Photo: 'images/VVS.jpg' },  
 { Name: 'Virendar Shewag', Photo: 'images/VS.jpg' },  
 { Name: 'Zaheer Khan', Photo: 'images/ZK.jpg' },  
 { Name: 'Sachin Tendulkar', Photo: 'images/ST.jpg' },  
 { Name: 'Mahender Singh Dhoni', Photo: 'images/MSD.jpg' },  
 { Name: 'Saurabh Ganguli', Photo: 'images/SG.jpg' },  
 { Name: 'Harbhajan Singh', Photo: 'images/HS.jpg' },  
 { Name: 'Youvrah Singh', Photo: 'images/YS.jpg' },  
 { Name: 'VVS Laxman', Photo: 'images/VVS.jpg' },  
 { Name: 'Virendar Shewag', Photo: 'images/VS.jpg' },  
 { Name: 'Zaheer Khan', Photo: 'images/ZK.jpg' }  
 ];  
 WinJS.Application.onmainwindowactivated = function (e) {  
 if (e.detail.kind === Windows.ApplicationModel.Activation.ActivationKind.launch) {  
 WinJS.UI.processAll().then(function () {  
 var PlayerList = document.getElementById('PlayerListView').winControl;  
 PlayerList.dataSource = PlayerData;  
 PlayerList.addEventListener('iteminvoked', SelectItem);  
 });  
 }  
 }  
 function SelectItem(e) {  
 var selectedItem = PlayerData[e.detail.itemIndex];  
 var selecteplayer = document.getElementById('selectedPlayer');  
 selecteplayer.innerText = selectedItem.Name;  
 var selecteplayerImg = document.getElementById('selectedPlayerImg');  
 selecteplayerImg.src = selectedItem.Photo;  
 }  
 WinJS.Application.start();  
 })();  
   
     Bu dosyada öncelikle html tarafına bağlamak istediğimiz verileri 'playerData' adlı değişkende tuttuk. Burada gördüğümüz üzere basit olarak isim ve fotoğraf bilgilerini girdik. Bunları daha sonra html tarafına bağlayıp bu verilerin kullanıcıya bir arayüzde gösterilmesi işlemini yapacağız.

 <!DOCTYPE html>  
 <html>  
 <head>  
 <meta charset="utf-8" />  
 <title>DataBindingPlayer</title>  
 <!-- WinJS references -->  
 <link rel="stylesheet" href="/winjs/css/ui-dark.css" />  
 <script src="/winjs/js/base.js"></script>  
 <script src="/winjs/js/ui.js"></script>  
 <script src="/winjs/js/binding.js"></script>  
 <script src="/winjs/js/controls.js"></script>  
 <script src="/winjs/js/animations.js"></script>  
 <script src="/winjs/js/uicollections.js"></script>  
 <script src="/winjs/js/wwaapp.js"></script>  
 <!-- DataBindingPlayer references -->  
 <link rel="stylesheet" href="/css/default.css" />  
 <script src="/js/default.js"></script>  
 </head>  
 <body>  
 <h2>Indian Team</h2>  
 <br />  
 <div id="playeritemtemplate"  
 data-win-control="WinJS.Binding.Template">  
 <div data-win-bind="innerText:Name"  
 style="height:20px;">  
 </div>  
 <img data-win-bind="src:Photo"  
 style="width:200px;height:150px;" />  
 </div>  
 <div id="PlayerListView"  
 data-win-control="WinJS.UI.ListView" style="height:185px;"  
 data-win-options="{itemRenderer:playeritemtemplate,layout:{type:WinJS.UI.GridLayout,maxRows:1}}" >  
 </div>  
 <br />  
 <div id="ouputDiv" >  
 <span>You Selected </span>  
 <span id="selectedPlayer" style="height:20px;" ></span> <br />  
 <img id="selectedPlayerImg" style="width:200px;height:150px;"/>  
 </div>  
 </body>  
 </html>  

     Evet bu kısımda da verilerimizin görüneceği sayfayı tasarladık. Bunun için öncelikle kullanıcı adı ve kullanıcı fotoğrafının nasıl gösterileceğine dair 'itemtemplate' oluşturduk ve bunun sonrasında da genel bir 'div' tagi içerisine 'daha önceden belirlediğimiz 'templateleri' yazdık. Bu son div tüm verileri kapsayan en genel div tagi olarak kullanıldı. Bu kısımda değinmek istediğim en önemli kısım kullandığımız resimde dikkatinizi çektiyse 'data-win-bind="src:Photo"' adlı bir ek özellik kullandık. Bu kısım bizim JavaScript dosyamızda oluşturduğumuz verilerin bu kısımda bağlanmasını içeriyor. JavaScript tarafında verilerimizi 'Name, Photo' şeklinde belirttik ve burada da aynı isimle bağladık.


    İlk yaptığımız projeye buradan indirebilirsiniz. Gelecek hafta görüşmek üzere...

Referanslar:
http://code.msdn.microsoft.com/windowsapps/DeclarativeBinding-bfcb42a5/view/Discussions#content
http://debugmode.net/2012/01/06/list-view-data-binding-in-windows-8-javascript-metro-application/

0 yorum:

Yorum Gönder