7

की अग्रिम :)मानचित्रण श्रेणीबद्ध JSON टाइपप्रति-KnockoutJS के लिए लिखा था वस्तु

ठीक में एक धन्यवाद के साथ शुरू करते हैं, तो मैं लोड/नॉकआउट का उपयोग कर JSON डेटा मिलान से टाइप किये गए वर्गों के नक्शे श्रेणीबद्ध टाइपप्रति/KnockoutJS कोशिश कर रहा हूँ। मैपिंग प्लगइन, पदानुक्रम एनएच डिग्री के लिए हो सकता है।

मुझे पता है कि मैं JSON डेटा से शीर्ष स्तर की कक्षा को मैप/लोड करने के लिए निम्न कार्य कर सकता हूं।

var qry = ko.mapping.fromJS(jsData, {}, new Query()); 

हालांकि मैं समझ नहीं टाइपप्रति/KnockoutJS कक्षाओं का एक सेट करने के लिए नक्शे के लिए कैसे/लोड जटिल, वां डिग्री, पदानुक्रमित JSON डेटा और माता पिता/बच्चे संबंध बनाने है।

मैंने अनगिनत कलाकृतियों को पढ़ा है, लेकिन जब वे सरल माता-पिता/बाल उदाहरणों से परे पदानुक्रमित संबंधों की बात करते हैं तो वे सभी कम हो जाते हैं, और मैं knockout.mapping प्लगइन का उपयोग करके कोई भी नहीं ढूंढ सकता।

यहां टाइपस्क्रिप्ट कक्षाओं की मेरी कट डाउन परिभाषाएं हैं जिन्हें मैं मानचित्र/लोड करना चाहता हूं। मैं एक सी ++/सी # डेवलपर हूं, इसलिए इस प्रकृति की जावास्क्रिप्ट मेरे लिए बहुत नई है।

टाइपप्रति ऑब्जेक्ट्स

JSON कुछ इस तरह दिखेगा:

{ 
    "ID": 2, 
    "Name": "Northwind 2", 
    "RootTargetID": 2, 
    "RootTarget": { 
     "ID": 2, 
     "Name": "Customers", 
     "ParentID": null, 
     "FilterID": 2, 
     "Queries": [], 
     "Children": [], 
     "Parent": null, 
     "Selects": [ 
      { 
       "ID": 3, 
       "Name": "CompanyName", 
       "Aggregation": "None", 
       "TargetID": 2, 
       "Target": null 
      }, 
      { 
       "ID": 4, 
       "Name": "ContactName", 
       "Aggregation": "None", 
       "TargetID": 2, 
       "Target": null 
      } 
     ], 
     "Filter": { 
      "FilterClauseID": 2, 
      "Type": "AND", 
      "Left": null, 
      "Right": null, 
      "ParentID": null, 
      "QueryTargets": [], 
      "Parent": null, 
      "Children": [ 
       { 
        "FilterClauseID": 3, 
        "Type": "NE", 
        "Left": "Country", 
        "Right": "Germany", 
        "ParentID": 2, 
        "QueryTargets": [], 
        "Parent": null, 
        "Children": [] 
       }, 
       { 
        "FilterClauseID": 4, 
        "Type": "NE", 
        "Left": "Country", 
        "Right": "Mexico", 
        "ParentID": 2, 
        "QueryTargets": [], 
        "Parent": null, 
        "Children": [] 
       } 
      ] 
     } 
    } 
} 
+0

समाधान – DIGGIDY

उत्तर

6

ठीक है, इसलिए मैं अब लाइन और नीचे एक छोटे से कर रहा हूँ, खींच बाल के बहुत सारे और numerious परीक्षणों के बाद ।

नीचे मैं जो कुछ हासिल करने की कोशिश कर रहा हूं उसका लगभग एक कामकाजी उदाहरण है, इसके साथ एकमात्र समस्या यह सही ढंग से मानचित्र नहीं लगती है, भले ही कोड के माध्यम से कदम उठाने का सुझाव है कि यह सही ढंग से लोड हो रहा है। केवल जब मैं इसे अपने बाइंडिंग के साथ उपयोग करता हूं तो यह रूटटागेट पर एक निरर्थक बाध्यकारी फेंकता है। फ़िल्टर। टाइप, जो किसी मान के साथ पॉप्युलेट होना चाहिए था।

मैं अभी भी यह पता लगाने की कोशिश कर रहा हूं कि क्यों, लेकिन मैं सुझावों का स्वागत करूंगा कि क्या संभव गलत है। :)

अब सुधार ली गई और काम

अर्द्ध काम कर टाइपप्रति

///<reference path="Scripts/typings/jquery/jquery.d.ts"/> 
///<reference path="Scripts/typings/knockout/knockout.d.ts"/> 
///<reference path="Scripts/typings/knockout.mapping/knockout.mapping.d.ts"/> 

module ViewModel 
{ 
    export class Query { 
     public ID: KnockoutObservable<number>; 
     public Name: KnockoutObservable<string>; 
     public RootTargetID: KnockoutObservable<number>; 
     public RootTarget: KnockoutObservable<QueryTarget>; 

     constructor(json: any) { 
      this.ID = ko.observable<number>(0); 
      this.Name = ko.observable<string>(); 
      this.RootTargetID = ko.observable<number>(); 
      this.RootTarget = ko.observable<QueryTarget>(); 

      var mapping = { 
       'RootTarget': { 
        create: function (args) { 
         return new QueryTarget(args.data, null); 
        } 
       } 
      }; 

      ko.mapping.fromJS(json, mapping, this); 

     } 
    } 

    export class QueryTarget { 
     public ID: KnockoutObservable<number>; 
     public Name: KnockoutObservable<string>; 
     public ParentID: KnockoutObservable<number>; 
     public Children: KnockoutObservableArray<QueryTarget>; 
     public Parent: KnockoutObservable<QueryTarget>; 
     public Selects: KnockoutObservableArray<QuerySelect>; 
     public FilterID: KnockoutObservable<number>; 
     public Filter: KnockoutObservable<FilterClause>; 

     constructor(json: any, parent: QueryTarget) { 
      this.ID = ko.observable<number>(0); 
      this.Name = ko.observable<string>(); 
      this.ParentID = ko.observable<number>(0); 
      this.Children = ko.observableArray<QueryTarget>(); 
      this.Parent = ko.observable<QueryTarget>(parent); 
      this.Selects = ko.observableArray<QuerySelect>(); 
      this.FilterID = ko.observable<number>(0); 
      this.Filter = ko.observable<FilterClause>(); 

      var mapping = { 
       'Children': { 
        create: function (args) { 
         return new QueryTarget(args.data, this); 
        } 
       }, 
       'Selects': { 
        create: function (args) { 
         return new QuerySelect(args.data, this); 
        } 
       }, 
       'Filter': { 
        create: function (args) { 
         return new FilterClause(args.data, null); 
        } 
       } 
      }; 

      ko.mapping.fromJS(json, mapping, this); 
     } 
    } 

    export class QuerySelect { 
     public ID: KnockoutObservable<number>; 
     public Name: KnockoutObservable<string>; 
     public Aggregation: KnockoutObservable<string>; 
     public TargetID: KnockoutObservable<number>; 
     public Target: KnockoutObservable<QueryTarget>; 

     constructor(json: any, parent: QueryTarget) { 
      this.ID = ko.observable<number>(); 
      this.Name = ko.observable<string>(); 
      this.Aggregation = ko.observable<string>(); 
      this.TargetID = ko.observable<number>(); 
      this.Target = ko.observable<QueryTarget>(parent); 

      ko.mapping.fromJS(json, {}, this); 
     } 
    } 

    export class FilterClause { 
     public FilterClauseID: KnockoutObservable<number>; 
     public Type: KnockoutObservable<string>; 
     public Left: KnockoutObservable<string>; 
     public Right: KnockoutObservable<string>; 
     public ParentID: KnockoutObservable<number>; 
     public Parent: KnockoutObservable<FilterClause>; 
     public Children: KnockoutObservableArray<FilterClause>; 

     constructor(json: any, parent: FilterClause) { 
      this.FilterClauseID = ko.observable<number>(); 
      this.Type = ko.observable<string>(); 
      this.Left = ko.observable<string>(); 
      this.Right = ko.observable<string>(); 
      this.ParentID = ko.observable<number>(); 
      this.Parent = ko.observable<FilterClause>(parent); 
      this.Children = ko.observableArray<FilterClause>(); 

      var mapping = { 
       'Children': { 
        create: function (args) { 
         return new FilterClause(args.data, this); 
        } 
       } 
      }; 

      ko.mapping.fromJS(json, mapping, this); 
     } 
    } 

    export class QueryModuleViewModel 
    { 
     public QueryObj: Query; 

     constructor() { 

      var json = { 
       "ID": 2, 
       "Name": "Northwind 2", 
       "RootTargetID": 2, 
       "RootTarget": { 
        "ID": 2, 
        "Name": "Customers", 
        "ParentID": null, 
        "FilterID": 2, 
        "Queries": [], 
        "Children": [], 
        "Parent": null, 
        "Selects": [ 
         { 
          "ID": 3, 
          "Name": "CompanyName", 
          "Aggregation": "None", 
          "TargetID": 2, 
          "Target": null 
         }, 
         { 
          "ID": 4, 
          "Name": "ContactName", 
          "Aggregation": "None", 
          "TargetID": 2, 
          "Target": null 
         } 
        ], 
        "Filter": { 
         "FilterClauseID": 2, 
         "Type": "AND", 
         "Left": null, 
         "Right": null, 
         "ParentID": null, 
         "QueryTargets": [], 
         "Parent": null, 
         "Children": [ 
          { 
           "FilterClauseID": 3, 
           "Type": "NE", 
           "Left": "Country", 
           "Right": "Germany", 
           "ParentID": 2, 
           "QueryTargets": [], 
           "Parent": null, 
           "Children": [] 
          }, 
          { 
           "FilterClauseID": 4, 
           "Type": "NE", 
           "Left": "Country", 
           "Right": "Mexico", 
           "ParentID": 2, 
           "QueryTargets": [], 
           "Parent": null, 
           "Children": [] 
          } 
         ] 
        } 
       } 
      } 

      //$.getJSON("/api/query/2", null, 
      // d => { 
      //  this.QueryObj = new Query(d); 
      // }) 

      this.QueryObj = new Query(json); 
     } 
    } 
} 

window.onload =() => { 
    ko.applyBindings(new ViewModel.QueryModuleViewModel()); 
}; 

एचटीएमएल बाध्यकारी परीक्षण

<!DOCTYPE html> 
<html lang="en"> 
<head> 
    <meta charset="utf-8" /> 
    <title>TypeScript Knockout Mapping Query Test</title> 
    <link rel="stylesheet" href="app.css" type="text/css" /> 

    <script src="Scripts/jquery-2.0.2.js" type="text/javascript"></script> 
    <script src="Scripts/knockout-2.2.1.debug.js" type="text/javascript"></script> 
    <script src="Scripts/knockout.mapping-latest.debug.js" type="text/javascript"></script> 
    <script src="query.js"></script> 
    <!--<script src="my_js_query_test_all.js"></script>--> 

</head> 
<body> 
    <h1>TypeScript Knockout Mapping Query Test</h1> 
    <div data-bind="with: QueryObj"> 
     <span data-bind="blah: console.log($context)"></span> 

     <p>Query Name: <input data-bind="value: Name" /></p> 

     <hr /> 
     <p>Quick test of RootTarget and Filter data</p> 
     <p>RootTarget.ID: <input data-bind="value: RootTarget().ID" /></p> 
     <p>RootTarget.Name: <input data-bind="value: RootTarget().Name" /></p> 

     <p>TYPE: <input data-bind="value: RootTarget().Filter().Type" /></p> 

     <hr /> 
     <p>RootTarget.FilterClause Hierarcy</p> 
     <div data-bind="with: RootTarget().Filter"> 
      <div data-bind="template: { name: 'QueryListClauseTemplate' }"></div> 
     </div> 

     <hr /> 
     <p>RootTarget.Selects</p> 
     <div data-bind="foreach: { data: RootTarget().Selects }"> 
      <div data-bind="template: { name: 'QueryListSelectsTemplate' }"></div> 
     </div> 

    </div> 

    <script type="text/template" id="QueryListClauseTemplate"> 

     <a title="FilterClause.Type" href="#" data-bind="text: Type" /> 

     <div data-bind="foreach: { data: Children }"> 
      <div data-bind="template: { name: 'QueryListClauseTemplate' }"></div> 
     </div> 
    </script> 

    <script type="text/template" id="QueryListSelectsTemplate"> 
     <a title="Select.Name" href="#" data-bind="text: Name" /> 
    </script> 

</body> 
</html> 
+0

नीचे जोड़ा जोड़ा एचटीएमएल परीक्षण कोड – DIGGIDY

+0

मामूली चूक के एक जोड़े फिक्स्ड, लेकिन अभी भी काम नहीं कर रहा अपेक्षा के अनुरूप। – DIGGIDY

+0

इस सवाल से दूर नहीं लग रहा है, मुझे लगता है कि टाइपस्क्रिप्ट प्रश्न की जड़ को जटिल बना सकता है। मैंने मूल कारण के साथ एक और सवाल पूछा है, [देखें LINK] (http://stackoverflow.com/questions/17612550/mapping-json-with-knockout-fails-to-populate-type-defined-object-properties) I जब मुझे कोई जवाब मिल जाए तो इसे एक हल्के समाधान के साथ अपडेट किया जाएगा। – DIGGIDY

1

एक और दृष्टिकोण है एक .d.ts फ़ाइल बनाने के लिए जो टाइपस्क्रिप्ट इंटरफेस को परिभाषित करता है जो आपके सी # कक्षाओं को नॉकआउट मैपिंग प्लगइन द्वारा उत्पन्न किए जाने वाले अवलोकन प्रकारों के नेस्टेड संग्रहों का वर्णन करता है।

फिर आपको .d.ts फ़ाइल का उपयोग करने की इच्छा रखने वाली टाइप-चेकिंग मिलती है (उसी तरह आप मौजूदा जावास्क्रिप्ट पुस्तकालयों के लिए टाइपिंग प्राप्त करने के लिए निश्चित रूप से टाइप किए गए जिथब प्रोजेक्ट से .d.ts फ़ाइल का उपयोग करेंगे)।

मैंने प्रतिबिंब का उपयोग करके अपने सी # डीएल की जांच करने के लिए एक कंसोल ऐप बनाया। मैंने उन प्रकारों को चिह्नित करने के लिए एक कस्टम विशेषता का उपयोग किया जिसके लिए टाइपस्क्रिप्ट इंटरफेस बनाए गए थे।(मुझे यह देखने के लिए एक कस्टम विशेषता भी बनाना था कि कौन से गुण देखने योग्य नहीं थे, क्योंकि मैपिंग प्लगइन केवल आपके नेस्टेड संग्रहों के पत्ते नोड्स को अवलोकन के रूप में बनाता है)।

यह मेरे लिए अच्छा काम करता है क्योंकि जब मैं अपना सी # मॉडल बदलता था तो मैं जल्दी से .d.ts फ़ाइल को पुन: उत्पन्न करने में सक्षम था। और मैं अपने नॉकआउट व्यूमोडेल के सभी हिस्सों के लिए टाइप-चेकिंग करने में सक्षम था।

//the custom attributes to use on your classes 
    public class GenerateTypeScript : Attribute 
    { 
     public override string ToString() 
     { 
      return "TypeScriptKnockout.GenerateTypeScript"; 
     } 
    } 

    public class NotObservable : Attribute 
    { 
     public override string ToString() 
     { 
      return "TypeScriptKnockout.NotObservable"; 
     } 
    } 


    //example of using the attributes 
    namespace JF.Models.Dtos 
    { 
     [TypeScriptKnockout.GenerateTypeScript] 
     public class ForeclosureDetails : IValidatableObject, IQtipErrorBindable 
     { 
      [TypeScriptKnockout.NotObservable] 
      public Foreclosure Foreclosure { get; set; } 

      //strings used for form input and validation 
      public string SaleDateInput { get; set; } 
      public string SaleTimeInput { get; set; }  
      ....etc. 



    //the console app to generate the .d.ts interfaces 
    void Main() 
    { 
     string dllPath = @"binFolder"; 
     string dllFileName = "JF.dll"; 
     Assembly assembly = Assembly.LoadFrom(Path.Combine(dllPath,dllFileName)); 
     List<string> interfacesToIgnore = new List<string>{"IValidatableObject"}; //stuff that won't exist on the client-side, Microsoft Interfaces 

     var types = from t in assembly.GetTypes() 
       where (t.IsClass || t.IsInterface) 
       && t.GetCustomAttributes(true).Any(a => ((Attribute)a).ToString() == "TypeScriptKnockout.GenerateTypeScript") 
       orderby t.IsClass, t.Name 
       select t; 

     Console.WriteLine("/// <reference path=\"..\\Scripts\\typings\\knockout\\knockout.d.ts\" />"); 

     foreach (var t in types) 
     { 

      //type 
      Console.Write("{0} {1}", " interface", t.Name); 

      //base class 
      if(t.BaseType != null && t.BaseType.Name != "Object"){ 
       Console.Write(" extends {0}", t.BaseType.Name); 
      }  

      //interfaces 
      var interfacesImplemented = t.GetInterfaces().Where (i => !interfacesToIgnore.Contains(i.Name)).ToList(); 
      if(interfacesImplemented.Count() > 0){ 
       Console.Write(" extends"); 
       var icounter = 0; 
       foreach (var i in interfacesImplemented) 
       { 
        if(icounter > 0) 
         Console.Write(","); 
        Console.Write(" {0}", i.Name); 
        icounter++; 
       } 
      } 
      Console.WriteLine(" {"); 

      //properties 
      foreach (var p in t.GetProperties()) 
      { 
       var NotObservable = p.GetCustomAttributes(true).Any(pa => ((Attribute)pa).ToString() == "TypeScriptKnockout.NotObservable"); 
       Console.WriteLine("  {0}: {1};", p.Name, GetKnockoutType(p, NotObservable)); 
      } 
      Console.WriteLine(" }\n");   

     } 
    } 


    public string GetKnockoutType(PropertyInfo p, bool NotObservable){ 

     if(p.PropertyType.Name.StartsWith("ICollection") 
     || p.PropertyType.Name.StartsWith("IEnumerable") 
     || p.PropertyType.Name.StartsWith("Dictionary") 
     || p.PropertyType.Name.StartsWith("List")) 
     {  
      return String.Format("KnockoutObservableArray<{0}>", p.PropertyType.GenericTypeArguments[0].Name); 
     } 
     var typeName = p.PropertyType.Name; 
     if(typeName.StartsWith("Nullable")) 
      typeName = p.PropertyType.GenericTypeArguments[0].Name; 


     switch (typeName) 
     { 
      case "Int32" : 
      case "Decimal" : 
       return NotObservable ? "number" : "KnockoutObservable<number>"; 

      case "String" : 
       return NotObservable ? "string" : "KnockoutObservable<string>"; 

      case "DateTime" :  
       return NotObservable ? "Date" : "KnockoutObservable<Date>"; 

      case "Boolean": 
       return NotObservable ? "boolean" : "KnockoutObservable<boolean>"; 

      case "Byte[]": 
       return NotObservable ? "any" : String.Format("KnockoutObservableAny; //{0}", typeName); 

      default: 
       if(NotObservable) 
        return typeName; 

       bool isObservableObject = true; 
       var subProperties = p.PropertyType.GetProperties(); 
       foreach (var subProp in subProperties) 
       { 
        if(
         subProp.PropertyType.IsClass 
         && !subProp.PropertyType.Name.StartsWith("String") 
         && !subProp.PropertyType.Name.StartsWith("ICollection") 
         && !subProp.PropertyType.Name.StartsWith("IEnumerable") 
         && !subProp.PropertyType.Name.StartsWith("Dictionary") 
         && !subProp.PropertyType.Name.StartsWith("List")    
        ) 
        { 
         isObservableObject = false; 
        }    
       } 

       return isObservableObject ? String.Format("KnockoutObservable<{0}>", typeName) : typeName;        
     } 
    } 

    //example of the interfaces generated 

    interface ForeclosureDetails extends IQtipErrorBindable { 
     Foreclosure: Foreclosure; 
     SaleDateInput: KnockoutObservable<string>; 
     SaleTimeInput: KnockoutObservable<string>; 
     ...etc. 
संबंधित मुद्दे