0

I'm thinking that I am not doing some part of this the "Angular Way" because I can't find similar use cases anywhere in the docs.

My input takes comma-separated inputs, and calls this function using ng-submit(within weatherController):

$scope.submit = function() {    

    var rawZipString = this.text;
    var strippedString = rawZipString.replace(/\s+/g, '');
    var zipArray = strippedString.split(',');

    for(i=0;i<zipArray.length;i++){
        Weather.getWeatherForecast(zipArray[i])
        .then(function(forecast){
            $scope.temperatures.push(forecast);
        })
    }

    /** Create weather objects */
    for(i=0;i<$scope.temperatures.length;i++){
            var tempForecast = new weatherConstructor(zipArray[i],$scope.temperatures[i]);
            $scope.zipForecast.push(tempForecast);
        }

    /** Format as JSON */
    $scope.DOMdata = angular.toJson($scope.zipForecast);
        console.log($scope.DOMdata);    
    }

This is weatherConstructor:

function weatherConstructor(zip,temp){
    this.zip = zip;
    this.temp = temp;
}

I'm unsure of how to then take the constructed JSON object ($scope.DOMdata) and push it to the view, which looks like this:

<div ng-controller="weatherController">
<h4 ng-repeat="DOM in DOMdata">
    {{DOM.zip}} now is {{DOM.temp}}
</h4>   

1
  • You're omitting some potentially important parts of the code, but I think the main issue is that getWeatherForecast runs asynchronously, but you are trying to use the results synchronously. Commented Dec 24, 2013 at 18:01

2 Answers 2

1

HTML: you need to use ng-model together with ng-list to automatically convert comma separated values into an array.

<input type="text" ng-model="text" ng-list>
<div ng-controller="weatherController">
<h4 ng-repeat="DOM in DOMdata">
  {{DOM.zip}} now is {{DOM.temp}}
</h4>

JS: you need to inject $q service here.

$scope.submit = function () {
  var zipArray = this.text;
  var all = [];
  for (i = 0; i < zipArray.length; i++) {
    var got = Weather.getWeatherForecast(zipArray[i])
      .then(function (forecast) {
        return forecast;
      })
    all.push(got);
  }

  // You have to wait until all temperatures are completed
  $q.all(all).then(function(forecasts) {

    // You have to assign temperature in here,
    // as forecasts may arrive at a different time
    // if you want to relay on the order of temperatures to match zipArray
    $scope.temperatures = forecasts;

    $scope.zipForecast = [];

    for (i = 0; i < $scope.temperatures.length; i++) {
      var tempForecast = new weatherConstructor(zipArray[i], $scope.temperatures[i]);
      $scope.zipForecast.push(tempForecast);
    }

    // you don't need toJson here, it is already a object
    $scope.DOMdata = $scope.zipForecast;
    console.log($scope.DOMdata);
  });
}


function weatherConstructor(zip,temp){
  this.zip = zip;
  this.temp = temp;
}
Sign up to request clarification or add additional context in comments.

1 Comment

This makes a lot more sense. I was sure there needed to be another chunk of promise architecture, but wasn't sure where.
0

I would like to answer your question about what about this code doesn't conform to the "Angular Way", and I would also like to suggest that you also make it a point of focus to write the simplest code possible. Indeed, I think that one of the best things about Angular is that it allows us to do very robust DOM manipulation with very simple javascript code (mostly!).

You have a misconception that you "send" your data to the DOM. In an Angular JS controller, every property of $scope is automatically bound to the UI. This means that you can both change the value of the $scope property through the DOM (by changing the value of an input, for example), and change the value programmatically in the controller (and that change will be immediately reflected in any representation of that property in the DOM.

So, for your problem, what I think would be best is to start with the end goal in mind. And I will make one suggestion here: let's use $scope.temperatures directly instead of renaming it to DOMdata. It's has more semantic value!

<h4 ng-repeat='item in temperatures'>
    {{item.zip}} now is {{item.temp}}
</h4>

Now in the controller, we can simplify the submit logic, if we want our data to look like this:

[{zip: 30224, temp: 30}, {zip: 90210, temp: 33}, {zip: 30695, temp: 28}]

Then perhaps the controller looks something like this:

weatherController = ['$scope', Weather,
    function($scope, Weather) {
        $scope.temperatures = [];
        $scope.text = '';

        $scope.submit = function() {
            this.temperatures = []; // clear it out
            var zipArray = this.text.replace(/s+/g, '').split(',');
            for(var i = 0; i < zipArray.length; i++) {
                Weather.getWeatherForecast(zipArray[i]).
                then(function(forecast) {
                    $scope.temperatures.push({zip: zipArray[i], temp: forecast});
                });
            }
         };
     }
];

And that should be it. Now, as is pointed out in another answer, filters are good for changing the display value, while leaving the underlying data intact. So:

{{item.zip}} now is {{item.temp | degrees}}.

1 Comment

This is incredibly clarifying as well, and your point about compactness is taken.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.