1

I've literally checked out every single ng-repeat question out there but a lot of them don't deal with databases and people just use arrays in JS and a simple $scope.array.push("stuff") works for them.

I've tried $scope.apply, $rootScope and even calling the GET request right after a successful POST request.

I have a form with 2 text inputs, date and content.
When the submit button is pressed, date and content are added into a MySQL database using PHP.

The data is added just fine to the MySQL database and retrieving also works properly.
Even the GET request inside the successful POST request is executed.
So I don't understand why it forces me to refresh the page to see the updated ng-repeat results.

Am I missing something?
Any help or suggestions is greatly appreciated, thanks!

The image


Relevant HTML code

<div ng-controller="insertController">
  <h2> What I learned today </h2>
  <form>
    Date <br>
    <input type="text" ng-model="date"><br><br>
      Content <br>
      <textarea rows="10" cols="50" ng-model="content"></textarea><br><br>
      <input type="button" value="Submit" ng-click="insertdata()">
  </form>
</div>

<div ng-controller="fetchController">
  <span ng-repeat="item in results">
    {{item.date}}<br>
    {{item.content}}<br><br>
  </span>
</div>

insertController.js

var app = angular.module('myApp', []);

app.controller('insertController', function($scope, $http) {
  $scope.insertdata = function() {
    $http({
      method: 'POST',
      url: 'http://localhost/storestuff/insert.php',
      data: {'date':$scope.date, 'content':$scope.content, 'in':'json-format'},
      headers: {'Content-Type': 'application/x-www-form-urlencoded'}
    })
    .then(function(res) {
      console.log("Successful response", res)
      $scope.date = "";
      $scope.content = "";
      $http.get('http://localhost/storestuff/fetch.php')
        .then(function successCallback(response) {
          alert("GOT NEW DATA");
          $scope.results = response.data; // Allow angular to access the PHP output data
      });
      $scope.apply;
    })
    .catch(function(err) {
      console.error("Error with POST", err);
    });
  }
});


insert.php
<?php

  header('Access-Control-Allow-Origin: *');

  $theConnection = mysqli_connect("localhost", "root", "", "storestuff");
  if(mysqli_connect_errno()) {
    echo "Failed to connect to MySQL.";
  }

  $theData = json_decode(file_get_contents('php://input'));
  $date = mysqli_real_escape_string($theConnection, $theData->date);
  $content = mysqli_real_escape_string($theConnection, $theData->content);

  mysqli_query($theConnection, "INSERT INTO thestuff(date, content) VALUES('$date', '$content')");

  mysqli_close($theConnection);

?>

fetchController.js

app.controller('fetchController', function ($scope, $http) {
  $http.get('http://localhost/storestuff/fetch.php')
    .then(function successCallback(response) {
      $scope.results = response.data; // Allow angular to access the PHP output data
  });
});


fetch.php
<?php
  header('Access-Control-Allow-Origin: *'); // clientside(Node) <-> serverside(PHP)

  $mysqli = new mysqli("localhost", "root", "", "storestuff");

  if($mysqli->connect_error) {
    printf("Connect failed: %s\n", $mysqli->connect_error);
    exit();
  }

  $query = "SELECT * FROM thestuff";
  $theData = array();

  if($result = $mysqli->query($query)) {
    while($row = mysqli_fetch_array($result)) {
      $theData[] = array(
        'date'=>$row['date'],
        'content'=>$row['content']);
    }
    echo json_encode($theData); // Echo the output for the controller to access
    $result->free(); // Free the result set
  }
  else {
    echo "0 results.";
  }
  $mysqli->close(); // Close the connection
?>
Ricky Dam
  • 1,833
  • 4
  • 23
  • 42
  • Shouldn't need to do another GET request for all that data when all you need to do is return the updated object posted to insert.php (with it's new id added) and push that into existing array – charlietfl May 14 '17 at 23:31

2 Answers2

2

The problem with this code is that you have two different controllers, both with separate scopes. Inserting/updating the $scope.results object/array in one controller, will not update the other $scope; they are separate distinct scopes, both with a copy of the data.

Using two controllers looks correct in your use case. However you should be using a service to access your remote data. Check out this answer for some advice on this https://stackoverflow.com/a/20181543/2603735.

Using a service like in that answer, will allow you to store the array/object of remote data in one place, and reference the SAME object from both controllers. Therefore updating from one controller, will also update the other.

Community
  • 1
  • 1
Jayden Meyer
  • 703
  • 2
  • 18
  • 28
  • Thank you. Your answer was very informative. But now, the `echo json_encode($theData)` gives me an undefined error. Any ideas? – Ricky Dam May 15 '17 at 01:09
  • That sounds like an error with the PHP code. Would have to see the full error to try and work it out – Jayden Meyer May 15 '17 at 01:58
0

For anyone who will ever stumble on my question, I don't want to just leave my broken code there with no answer but neither can I edit the question and put in my answer cause that would defy the purpose of StackOverflow.

So here is my answer to my own question.

I had to make quite a few changes to what I had before. The biggest change by far, is how I handled the data that was returned by fetch.php.

Instead of just taking the output into $scope.results = response.data;, which would work fine if I wasn't dynamically adding to the database, but for this case, I ended up using a service.
(Thanks @jayden-meyer for suggesting Angular services.)

The service allowed me to access the same array from my insertController and from my fetchController instead of having a copy of the same array in both controllers which was my problem.


No changes in the HTML code.
No changes to insert.php.
No changes to fetch.php.


insertController.js
I removed the extraneous GET request I had inside the .then method which was completely unneeded since I can just push to the existing array.
(Thanks @charlietfl for the tip)
Instead I added resultsService.addItem($scope.date, $scope.content); inside of the .then method.
I also added my service as an argument.
app.controller('insertController', function($scope, $http, resultsService) {


result.js

app.service('resultsService', function() {
  var results = new Array();

  var addItem = function(date, content) {
    var obj = new Object();
    obj["date"] = date;
    obj["content"] = content;
    results.push(obj);
  }

  var getItems = function() {
    return results;
  }

  return {
    addItem: addItem,
    getItems: getItems
  };

});

fetchController.js

var size = 0;
var count = 0;

app.controller('fetchController', function ($scope, $http, resultsService) {
  $http.get('http://localhost/storestuff/fetch.php')
    .then(function successCallback(response) {
      size = (response.data).length;
      while(count < size) {
        var date = response.data[count].date;
        var content = response.data[count].content;
        resultsService.addItem(date, content);
        count++;
      }
      size = 0;
      count = 0;
      $scope.results = resultsService.getItems();
  });
});
Ricky Dam
  • 1,833
  • 4
  • 23
  • 42