2017-01-02 5 views
-1

Was ich hier erreichen möchte, ist ein strukturierter Datensatz zum Rendern einer Zeitleiste aus dem Array "timeTree".Zugriff auf den Kontext des neu gestoßenen Objekts im Array

Zuerst übertrage ich Ziele, die Enddatum haben. Basierend auf diesem Datum möchte ich kategorisieren sie in die richtige Jahr und Monat.

Angular für die Darstellung verwendet wird, und ich hatte keine Probleme mit dieser Struktur zu machen, kann man das nicht über das Erstellen gesagt werden ...

Meine Frage ist, wie ein Tor in das Jahr hinzuzufügen, das ist noch nicht im Array?

scope.timeTree = []; 
_.each(goals, function(goal) { 
    if (goal.stateId != "FINISHED") { 

     var goalYear = new Date(goal.plannedEnd).getFullYear(); 
     var goalMonth = new Date(goal.plannedEnd).getMonth(); 

     if (scope.timeTree.length > 0) { 
     _.each(scope.timeTree, function(year) { 
      if (year.year === goalYear) { 
      _.each(year.months, function(month) { 
       if (month.month === goalMonth) { 
       month.goals.push(goal); 
       } else { 
       year.months.push({ 
        month: goalMonth, 
        goals: [] 
       }); 
       _.each(month.goals, function(goal) { 

       }) 
       } 
      }) 
      } else { 
      scope.timeTree.push({ 
       year: goalYear, 
       months: [] 
      }); 

      _.each(year.months, function(month) { 
       if (month.month === goalMonth) { 
       month.goals.push(goal); 
       } else { 

       } 
      }); 
      } 
     }) 
     } else { 
     // init structure 
     scope.timeTree.push({ 
      year: goalYear, 
      months: [] 
     }); 
     _.each(scope.timeTree, function(year) { 

      year.months.push({ 
      month: goalMonth, 
      goals: [] 
      }); 

      _.each(year.months, function(month) { 

      month.goals.push(goal); 


      }); 
     }); 
     } 
    } 
    } 
} 

In dem obigen Code, speziell, wenn year.year zu goalYear nicht gleich ist, ich einfach nicht wissen, was zu tun ist ... ich im Rahmen des Jahres bin (Objekt mit Informationen über das Jahr , und Monate in diesem Jahr, die Ziele haben) Aber ich möchte nicht über Monate im Kontext des Jahres iterieren, was nicht gleich dem Jahr des Ziels ist. Ich möchte das Tor in das Feld der Monate schieben, in dem ich gerade gestoßen bin. Grundsätzlich ist das Hauptproblem mit negativen Zweigen von if-Anweisungen, wenn ich neue Objekte in das Array schieben muss und gleichzeitig das Ziel in die Arrays schiebe, die gerade erstellt (pushed) wurden. Vielleicht ist das nicht einmal ein guter Ansatz, also bin ich offen für bessere Lösungen. Auf der anderen Seite wäre es schön, wenn Sie wüssten, wie dieser genaue Ansatz funktioniert.

Antwort

0

Ich denke, die tiefe Verschachtelung und Iterationen macht es einfach, verwirrenden Code zu schreiben. Wenn es keinen guten Grund gibt, Vanille JS nicht zu verwenden, sollte es für die vorliegende Aufgabe mehr als ausreichend sein. Natürlich sollte das Schreiben des Codes ohne tiefe Verschachtelung hier die höchste Priorität haben.

Beispiel:

// In scope.timeTree, return me an array objects where it's year value matches goalYear 
var matching_year = scope.timeTree.filter(function(yearly_goal) { 
    return yearly_goal.year === goalYear; 
}); 

// If it does not exists, create one 
// Else, use that - there should only be 1 
if (matching_year.length === 0) { 
    var newTimeTree = {year: goalYear, months: []}; 
    matching_year = newTimeTree; 
    scope.timeTree.push(newTimeTree); 
} else { 
    matching_year = matching_year[0]; 
} 

// From the object with the matching year, find the object with the matching goalMonth 
var matching_month = matching_year.months.filter(function(monthly_goal) { 
    return monthly_goal.month === goalMonth; 
}); 

// If it does not exists, create one 
// Else, use that one 
if (matching_month.length === 0) { 
    var newGoal = {month: goalMonth, goals: []}; 
    matching_month = newGoal; 
    matching_year.months.push(newGoal); 
} else { 
    matching_month = matching_month[0]; 
} 

// Finally, pushed goal into the object that matches the year and the month 
matching_month.goals.push(goal); 

Edit: Natürlich, wenn es sein muss, bemerkte ich, dass Sie Underscore.js für Ihre _.each (Liste, iteratee) verwenden. In diesem Fall können Sie die Filterfunktion von Vanilla JS für die Filterfunktion von Unterstrich JS ersetzen, wie in here definiert.

0

Sie könnten Map (ES6-Funktion) verwenden, um das Jahr und den Monat, den Sie suchen, schnell (in konstanter Zeit) zu finden. Und dann Array.from verwenden, die verschachtelte Map Struktur auf den endgültigen zu konvertieren:

var scope = {}; // for snippet only 
 
// Sample data 
 
var goals = [ 
 
    { plannedEnd: '2015-12-01', text: 'Break', stateId: 'STARTED' }, 
 
    { plannedEnd: '2016-07-01', text: 'Break', stateId: 'STARTED' }, 
 
    { plannedEnd: '2016-01-01', text: 'Year', stateId: 'STARTED' }, 
 
    { plannedEnd: '2016-01-01', text: 'New', stateId: 'STARTED' }, 
 
    { plannedEnd: '2015-12-01', text: 'Christmas', stateId: 'STARTED' }, 
 
    { plannedEnd: '2016-07-01', text: 'Summer', stateId: 'STARTED' }, 
 
]; 
 

 
scope.timeTree = Array.from(
 
    goals.filter(goal => goal.stateId != "FINISHED") 
 
     .reduce((yearMap, goal) => { 
 
      var goalYear = new Date(goal.plannedEnd).getFullYear(); 
 
      var goalMonth = new Date(goal.plannedEnd).getMonth(); 
 
      // Store year in map. Create new entry if not yet there 
 
      if (!yearMap.has(goalYear)) yearMap.set(goalYear, new Map); 
 
      var monthMap = yearMap.get(goalYear); 
 
      // Same principle for month: 
 
      if (!monthMap.has(goalMonth)) monthMap.set(goalMonth, []); 
 
      monthMap.get(goalMonth).push(goal); 
 
      return yearMap; 
 
     }, new Map), // Start with empty Map 
 
    // Now convert to final structure, with second arg to main Array.from 
 
    ([year, monthMap]) => ({ 
 
     year, 
 
     months: Array.from(monthMap, ([month, goals]) => ({month, goals})) 
 
      // Optionally sort months 
 
      .sort((a,b) => a.month - b.month) 
 
    }) 
 
// Optionally sort the array by year 
 
).sort((a,b) => a.year - b.year); 
 

 
    
 
console.log(scope.timeTree);
.as-console-wrapper { max-height: 100% !important; top: 0; }

0

Vielen Dank für Hilfe. Das Projekt, für das ich das benötigte, ist in es5 gebaut, so dass die Verwendung einer neuen JavaScript-Spezifikation keine Option war, aber ich werde es trotzdem in persönlichen Projekten verwenden. KnightNiwrem, ich musste die Referenzen zum Rendering behalten, also habe ich anstelle des Filters die Pick-Methode vom Unterstrich benutzt. Dies ist die endgültige Lösung.

_.each(value, function(goal) { 
          if (goal.stateId != "FINISHED"){ 

           var goalYear = new Date(goal.plannedEnd).getFullYear(); 
           var goalMonth = new Date(goal.plannedEnd).getMonth(); 

           var matchingYear = _.find(scope.timeTree, function(year){ 
            return year.year === goalYear; 
           }) 

           if (!!matchingYear){ 
            var matchingMonth = _.find(matchingYear.months, function(month){ 
             return month.month === goalMonth; 
            }) 

            if (!!matchingMonth){ 
             matchingMonth.goals.push(goal); 
            } 
            else{ 
             matchingYear.months.push({ month: goalMonth, goals: [goal] }); 
            } 
           } 
           else{ 
            var newStructure = { year: goalYear, 
                 months: [{ month: goalMonth, goals: [goal] }] 
            } 

            scope.timeTree.push(newStructure); 
           } 
          } 
         }) 
Verwandte Themen