0

I am a little confused about how to pass my database data loaded in a controller to another controller.

I load some list items from the server and on each item click I want to open the details about that item on another screen according to its id.

I read some questions about making a service or use $rootScope but $rootScope should be avoid as much as possible.

What is the best way of doing this in my case and could you show me how to do it? Should I load the data inside a service or there is an easiest way in my case?

list item using 1st controller:

<div class="item item-body list-container" id="temporada2016-list-item-container4" ng-model="item_id" ng-repeat="x in items" item="x" href="#/x/{{x.ID}}" ng-click="open_item(x)" ng-show="news_list">

        <div id="temporada2016-markdown7" style="margin-top:0px;color:#666666;">
            <h2 style="color:#008BBB;">{{ x.TITLE }}</h2>
        </div>

</div>

1st controller

.controller('temporada2016Ctrl', ['$scope', '$http', function ($scope, $http) {

$scope.active_news_btn = true;
$scope.search_news = true;
$scope.news_list = true;
$scope.albums_list = false;

$http.get("http://localhost/select-news.php").then(function(response){

    console.log(response);
    console.log(JSON.stringify(response));

    $scope.items = response.data;

});

$scope.open_item = function(x){

    //alert("Item id: " + x.ID);
    $http.post("http://localhost/select-news-by-id.php", {'item_id': x.ID}).then(function(response){

    console.log(response);
    console.log(JSON.stringify(response));

    $scope.all = response;
    $scope.title = response.data[0].TITLE;
    $scope.body = response.data[0].BODY;


 });


 }
}])

second screen (details) using 2nd controller where I want to load the same title and news body

<ion-view title="Detalhes" id="page4" style="background-color:#FFFFFF;">
  <ion-content padding="true" class="has-header">
    <h3 id="detalhes-heading1" style="color:#008BBB;font-weight:600;font-style:italic;">{{title}}</h3>
    <div id="detalhes-markdown3" style="color:#000000;">
        <p>{{body}}</p>
    </div>
    <form id="detalhes-form4" class="list">
        <button id="detalhes-button6" style="color:#008BBB;text-align:left;border-radius:9px 9px 9px 9px;" class="button button-calm  button-clear icon ion-ios-heart-outline like_btn"></button>
        <label class="item item-input" id="detalhes-textarea1">
            <span class="input-label"></span><textarea placeholder=""></textarea>
        </label>
    </form>
    <button id="detalhes-button17" style="color:#FFFFFF;" class="button button-positive">Comment</button>
  </ion-content>
</ion-view>

2nd controller

.controller('detalhesCtrl', ['$scope', '$stateParams', function ($scope, $stateParams) {


}])

PHP

<?php 

include_once('conn.php');

$data = json_decode(file_get_contents("php://input"));

if(property_exists($data, 'item_id')){

$item_id = $data->item_id;
$sql = $mysqli->query("SELECT * FROM news WHERE id = '".$item_id."'");

if($sql->num_rows > 0){
        while($row = $sql->fetch_array(MYSQLI_BOTH)){
            $registro = array(
                "ID" => $row['id'],
                "TITLE" => $row['title'],
                "BODY" => $row['body']
                );

        $retorno[] = $registro;

        }   
}

    $mysqli->close();
    $retorno = json_encode($retorno);
    echo $retorno;

}

?>
madsongr
  • 653
  • 1
  • 11
  • 29

3 Answers3

1

In your app-config

$stateProvider
      .state('master', {
        url: '/master',
        templateUrl: 'views/master.html',
        controller: 'MasterCtrl',
        data: {
          someThingToPassToMasterState: false
        }
      })
      .state('details', {
        url: '/details',
        data : {
          somethingToPassToDetailsState: false
        },
        templateUrl: 'views/details.html',
        controller: 'DetailsCtrl'
      });

And then in your MasterCtrl

$scope.onClick = function(obj) {
  var dataToPass = {};
  dataToPass.obj = obj;
  dataToPass.somethingElse = 'blah blah';
  $state.go('details', {somethingToPassToDetailsState: dataToPass});
}

// Now in the DetailsCtrl
if(!$state.params.somethingToPassToDetailsState) {
  // handle this  
  // maybe do a $state.go('default') and then return to end execution of this controller
}

// Some code

In master.html, using ng-repeat to simulate master-details page redirection

<div ng-repeat="o in objects">
  <div ng-click="redirectTo(o)">{{o.name}}</div>
</div>

The idea is to pass day directly from one state to another on state transition. You can either pay in I'd and make api call AFTER transitioning to these new state or get the response from api and then paas required data to the next state

SLearner
  • 1,419
  • 5
  • 18
  • 22
  • what you are saying is to send the id from the list item to DetailsCtrl to execute the $http.post method and load the data inside this controller? – madsongr Sep 05 '16 at 20:26
  • You can make api call after being redirected or you can make api call and then on response do $state.go(). Whichever way you want to do it – SLearner Sep 05 '16 at 20:51
  • ReferenceError: $state is not defined on line $state.go('details', {dataToDetails: dataToPass}); – madsongr Sep 05 '16 at 21:05
  • 1
    Inject $state into your controller – SLearner Sep 06 '16 at 04:37
  • it is falling in the condition if(!$state.params.somethingToPassToDetailsState) { // handle this } even with the data being the corresponding one. – madsongr Sep 07 '16 at 21:42
  • it is working now. I changed data : { somethingToPassToDetailsState: false } to params: { somethingToPassToDetailsState: false }. Thanks man! – madsongr Sep 08 '16 at 19:47
  • do you know if I can reload the list using this method when I press the back Button? It is displaying the same list item everytime in details page. I tried $state.reload() but it did not work. – madsongr Sep 09 '16 at 14:35
  • Solved. I just set cache: false on stateProvider. – madsongr Sep 09 '16 at 16:07
0

Share data between two controller is not good practice.

We need to put the data in service which can easily be shared with any number of controllers

Service: MyService

this.dbDataSearch = function(parameters){
  // Search record from database
  this.resultData = data;
}

In Convtoller 1:

 $scope.data = MyService.resultData;

In Convtoller 2:

 $scope.data = MyService.resultData;

....

In Convtoller n:

 $scope.data = MyService.resultData;

Once service variable will update all these controller variables automatically updated.

Ali Adravi
  • 21,707
  • 9
  • 87
  • 85
0

First of all, it is highly recommended you make your http calls in a factory or a service. This will make your code more reusable and it will look something like this:

app.factory("responseFactory", function($http) {
  return {
      getData: function() {
          //Code for making http call goes in here
          $http.get("http://localhost/select-news.php").then(function(response){
            return(response.data);
          });
      },
      postData: function(x) {
          $http.post("http://localhost/select-news-by-id.php", {'item_id': x.ID})
          .then(function(response){
            return(response.data);
          });
      }
  };
});

You could later use this to call in your controller by injecting this factory in your controller and calling this factory something like this:

app.controller('temporada2016Ctrl', ['$scope', 'responseFactory', function ($scope, responseFactory) {
    $scope.items = responseFactory.getData();
    $scope.opnItem = function(x){
        $scope.all = responseFactory.postData(x);
        $scope.title = all.TITLE;
        $scope.body = all.BODY;
    }
}]);

Now, to make the data available in your second controller, you could do a few things.

  1. Pass it through the $rootScope, which as you already said, should be avoided as much as possible to not clutter the rootScope. It can have many consequences. - NOT RECOMMENDED

  2. Make a service call from the second controller and you will have all the data you need from the api. However, if you edit the data in the first controller and wish to make edited data available in the second controller, that will not be possible using this method. Also, making http calls is costly and it highly recommended to minimize your number of http calls in the app. - NOT RECOMMENDED

  3. Use Angular service/factory - HIGHLY RECOMMENDED

    app.factory('commonData', function() {
        var data;
    
        return{
            setData: setData,
            getData: getData
        };
    
        //setter
        function setData(dataToBeShared) {
            data = dataToBeShared;
        }
    
        //getter
        function getData() {
            return data;
        }
    
    });
    

    Now you can inject this factory into your controllers and use the setter and getter methods easily. DO not forget to inject the responseFactory which we created earlier! After injecting it into your first controller, you can call the commonData factory and use the setter method to set the data, something like this:

    app.controller('temporada2016Ctrl', ['$scope', 'responseFactory', 'commonData', function ($scope, responseFactory, commonData) {
    
        //All your controller code, including calling the factory like I earlier explained...it all goes here
    
        commonData.setData(passTheDataThatYouWantToShare);
    
    }]);
    

Now, to get the data in the other controller, all you need to do is access the factory's getter method and you get the data! That will be something like this:

    app.controller('detalhesCtrl', ['$scope', '$stateParams', 'commonData', function ($scope, $stateParams, commonData) {
        $scope.commonData = commonData.getData();
        //Use $scope.commonData to use all the data that has come in from first controller
    }]);

Now, the data that is passed from controller 1 is stored in the factory and can be retrieved in the second controller whenever you want. Suppose you would like to display them as panes, next to each other, you might want to add watchers, otherwise this method should work fine for you.

NOTE: This can be achieved without using setter and getter methods, but using them is a good practice and is very useful when an app gets bigger.

  1. Pass data through state params using Angular UI router. It seems to me that you are using Angular UI router which comes bundled with ionic. This can also be used when you are routing. At the time of writing this answer, another answer on this thread (by SLearner) has already explained this method and if it is recommended or not is more or less your choice depending on the level of functionality you want. However, in my opinion, I would not go in with this solution. You can find some more answers on this topic on this thread: AngularJS: Pass an object into a state using ui-router

So, concluding my answer, in my opinion, it is best you go in for an angular factory. IMHO, that is the best solution. Hope your queries are answered.

Cheers!

Community
  • 1
  • 1
Mohammed Azhar
  • 260
  • 4
  • 18
  • getData() is loading data when I use console.log(JSON.stringify(response)); but nothing is displayed on the list after using $scope.items = responseFactory.getData(); in controller – madsongr Sep 05 '16 at 21:49
  • You might want to check if the values are getting stored in $scope.items. Keep breakpoints and debug the app and check if the data is getting loaded in the scope. Logging the scope might also be of some help. It is recommended you use the $log service provided by angular instead of console.log. You can also try directly logging responseFactory.getData() and check if the factory is returning the data. – Mohammed Azhar Sep 06 '16 at 09:05
  • If the factory does not send data back, you could try handling the success outside the factory by doing something like this in responseFactory: getData: function () { return $http.get("http://localhost/select-news.php") } In such case, you return only the http call and do not handle the success or error case in the factory. You can simple call the factory and handle the success or error in controller like: responseFactory.getData().success(function(data,status, headers,config){ $scope.items=data; }); Same goes with postData as well. – Mohammed Azhar Sep 06 '16 at 18:00
  • ok, I can get the list items now with getData: function () { return $http.get("localhost/select-news.php") }. How should I manage post now? I have to send ng-model="item_id" to php to get data according to it. See my PHP at my edited question, please. – madsongr Sep 07 '16 at 20:49
  • Try this: In responseFactory under postData function: postData: function(x) { return $http.post("http://localhost/select-news-by-id.php", {'item_id': x.ID}) } In controller: responseFactory.postData(x).then(function(response){$scope.all = response.data;}) Check if this works! – Mohammed Azhar Sep 08 '16 at 09:55
  • I have done that. It returned me "x" or "x.ID" undefined in factory. So I had to remove it leaving Just the $http.post("localhost/select-news-by-id.php"); – madsongr Sep 08 '16 at 14:50