Laden...

AngularJS mit SignalR gleicher Controller, gleiches Model unterschiedliche Daten. Wie vorgehen?

Erstellt von Zicore vor 8 Jahren Letzter Beitrag vor 8 Jahren 2.373 Views
Z
Zicore Themenstarter:in
403 Beiträge seit 2007
vor 8 Jahren
AngularJS mit SignalR gleicher Controller, gleiches Model unterschiedliche Daten. Wie vorgehen?

Ich habe eine View die mehrfach auf einer Seite angezeigt werden kann.
Zudem habe ich ein Angular Controller der sich um diese View kümmern soll.

Meine Merkmale sind die @Model.Id und @Model.Pair.Key. Die kann ich auch dem Hub übergeben und bekomme die entsprechenden Daten, aber wie bekomme ich die Daten in models.ticker nur für die entsprechende View?

Ich verwende die $attrs um die Parameter im vorraus festzulegen und die Lösung funktioniert zwar, erscheint mir aber nicht sehr elegant.

Zudem muss ich die Daten derzeit Serverseitig zyklisch bereitstellen. Aber das ist ein anderes Problem.

Gibt es da eine bessere Lösung?


@using IntTrader.API;
@inherits Nancy.ViewEngines.Razor.NancyRazorViewBase<IntTrader.Web.Model.ExchangeModel>

<div class="col-xs-4 col-sm-2 placeholder" ng-controller="ExchangeController" data-exchange="@Model.Id" data-pair="@Model.Pair.Key">
    <h3 class="blue"><a href="/markets/@Model.Name.ToLower()">@Model.Name</a></h3>
    <div class="modal-title" ng-model="models.ticker">{{models.ticker.lastPrice}}</div>
    <div class="center-block">
        <table class="trades" id="trades-@Model.Id"></table>
    </div>
</div>
'use strict';

app.controller('ExchangeController', ['$scope', 'backendHubProxy','$attrs',
  function ($scope, backendHubProxy, $attrs) {

      console.log('trying to connect to service');
      var tickerHub = backendHubProxy(backendHubProxy.defaultServer, 'TickerHub');
      console.log('connected to service');

      $scope.tickerHub = tickerHub;

      tickerHub.on('update', function(data) {
          console.log($scope.exchange);
          if (data.id === $attrs.exchange){
              $scope.models = {
                  ticker: data
              };
          }
      });
  }
]);
'use strict';

app.factory('backendHubProxy', ['$rootScope', 'backendServerUrl',
  function ($rootScope, backendServerUrl) {

      function backendFactory(serverUrl, hubName) {
          var connection = $.hubConnection(backendServerUrl);
          var proxy = connection.createHubProxy(hubName);

          connection.start().done(function () { });

          var hub = {
              on: function(eventName, callback) {
                  proxy.on(eventName, function(result) {
                      $rootScope.$apply(function() {
                          if (callback) {
                              callback(result);
                          }
                      });
                  });
              },
              invoke: function(methodName, p1, p2, callback) {
                  proxy.invoke(methodName, p1, p2)
                      .done(function(result) {
                          $rootScope.$apply(function() {
                              if (callback) {
                                  callback(result);
                              }
                          });
                      });
              }
          };
          return hub;
      };

      return backendFactory;
  }]);
16.807 Beiträge seit 2008
vor 8 Jahren

Ich hab das jetzt versucht mehrfach zu verstehen, was die Ausgangslage ist und was das Problem ist.
Wurde trotzdem nicht schlau draus 😉

Z
Zicore Themenstarter:in
403 Beiträge seit 2007
vor 8 Jahren

Das Grundproblem ist, dass das Model im Controller überschrieben wird, wenn ich die Abfrage mit

if (data.id === $attrs.exchange)

nicht drin habe, da das event logischerweise pro Instanziierung des Controllers gefeuert wird.

Ich bin derzeit darauf angewiesen die Daten mit data-exchange="@Model.Id" data-pair="@Model.Pair.Key" im vorraus mit zu übergeben. Die ja dann im $attrs zu finden sind.

Im Anhang noch ein Bild.

Wenn die Erklärung noch nicht reicht, versuche ich das mal in einem minimal Beispiel zusammenzufassen 😉

16.807 Beiträge seit 2008
vor 8 Jahren

Das eine wird Serverseitig ausgeführt (Schritt 1) das andere Clientseitig (Schritt 2).
Diese Reihenfolge zu ändern ist erstmal so nicht möglich.

Das (ASP.NET MVC und Angular) zu mischen ist ohnehin keine soooo tolle Idee.
Was genau willst Du den erreichen? Ich versteh das Ziel und das Problem leider aus dem Context immer noch nicht.
Modelle bzw. Daten, die Du via MVC renderst können nicht über die Standard-Methoden von MVC in den Angular DOM fallen.

Ich weiß nicht, ob das jetzt ein Controller von Angular ist oder von MVC und Deiner Grafik; aber ein Hub hängt in Angular eigentlich nicht in einem Controller.
Auch in Angular sollte man hier die Schichten trennen und sich für die API-Kommunikation ein Repository(Angular Factory) bauen, das die Daten dann in einen Service (Angular Service) lädt.
Das Hub selbst ist dabei an den Service gebunden, dass dessen Daten aktualisiert.
Der Controller kennt wiederum nur den Service, das dann die Daten an die View bindet.

Eine Angular App hat ebenso das recht auf eine 3-Schichten-Architektur.

Z
Zicore Themenstarter:in
403 Beiträge seit 2007
vor 8 Jahren

Auf dem Bild sind Angular Controller und Razor Partials (Views), das können in Zukunft noch Angular Partials werden, aber das sollte noch kein Problem darstellen.

Der Hub wird in einem Service bzw. einer Factory bereitgestellt.

Im Controller binde ich mich an das on Event des Hubs und dieses Event wird pro Controller ausgeführt, immer wenn der Hub Daten sendet und damit das model nicht für die falsche View geschrieben wird muss ich diese Abfrage machen:

if (data.exchange === $attrs.exchange && data.Pair.Key === $attrs.pair) {
    $scope.ticker = data;
}

Denn ansonsten wird $scope.ticker immer wieder überschrieben und habe am ende immer gleichen Wert überall drin.

Mittlerweile sieht das so aus:

'use strict';

app.controller('ExchangeController', ['$scope', 'backendHubProxy','$attrs',
  function ($scope, backendHubProxy, $attrs) {

      console.log('trying to connect to service');
      var tickerHub = backendHubProxy(backendHubProxy.defaultServer, 'ExchangeHub');
      console.log('connected to service');

      $scope.tickerHub = tickerHub;

      //------------------

      tickerHub.on('updateTicker', function (data) {
          if (data.exchange === $attrs.exchange && data.Pair.Key === $attrs.pair) {
              $scope.ticker = data;
          }
      });

      tickerHub.start().done(function () {
          var args = [$attrs.exchange, $attrs.pair];
          tickerHub.invoke('RequestTicker', args, function (data) { });
      });

      //------------------

      tickerHub.on('updateTrade', function (data) {
          if (data.exchange === $attrs.exchange) {
              $scope.trades = data.trades;
          }
      });

      tickerHub.start().done(function () {
          var args = [$attrs.exchange, $attrs.pair];
          tickerHub.invoke('RequestTrade', args, function (data) { });
      });

      //------------------

      tickerHub.on('updateBalance', function (data) {
          if (data.exchange === $attrs.exchange) {
              $scope.balances = data.balances.Items;
          }
      });

      tickerHub.start().done(function () {
          var args = [$attrs.exchange, $attrs.pair];
          tickerHub.invoke('RequestBalance', args, function (data) { });
      });
  }
]);
'use strict';

app.factory('backendHubProxy', ['$rootScope', 'backendServerUrl',
  function ($rootScope, backendServerUrl) {

      function backendFactory(serverUrl, hubName) {
          var connection = $.hubConnection(backendServerUrl);
          var proxy = connection.createHubProxy(hubName);

          var hubStart = null;

          var hub = {
              on: function (eventName, callback) {
                  proxy.on(eventName, function (result) {
                      $rootScope.$evalAsync(function () {
                          if (callback) {
                              callback(result);
                          }
                      });
                  });
              },
              invoke: function (methodName, args, callback) {
                  proxy.invoke.apply(proxy, $.merge([methodName], args))
                      .done(function (result) {
                          $rootScope.$evalAsync(function () {
                              if (callback) {
                                  callback(result);
                              }
                          });
                      });
              },
              start: function () {
                  if (hubStart === null) {
                      hubStart = connection.start();
                  }
                  return hubStart;
              }
          };
          return hub;
      };

      return backendFactory;
  }]);

Nach langem rumprobieren und erklären, denke ich, verstehe ich mittlerweile, wo ich anpacken muss.

Ich werde das später nochmal durchgehen.

Danke für deine Anregungen.