[solved] Using href in sidemenu to change only the data in content view

The side-menu starter application has a number of items in the side menu, each with its own controller for the main content area. I want to have a bunch of side-menu items that share a controller, but represent different data to be displayed.

Think of it this way: The side menu shows the names of a bunch of projects, and tapping one name loads up that project in the main content view. The projects are all the same in structure, but have different data.

I’d love to do this with hrefs, like “#/projects/1” and “#/projects/2” but I can’t get the router to load up new data in the controller. Is there a hook that I’m missing? Should I just go with an ngClick mechanism (which feels kinda gross)?

Thanks!

Hi!

Just to be sure, if I understand your request correctly, you want to make something similar to ion-tabs or jQuery UI tabs but the difference would be that when you click on an item, you keep the same template, just update it with different data (keeping the same architecture). Am I right?

Yup, that seems about right.

Something like this?

1 Like

Perfect. Thanks!! <3

How do i access the data from $resource?

I have a backend that i need to connect to and which looks like “empty” result. I believe the data is there but ionic does not parse the data well. if i put “var jobs = [ id: 0, title: ‘name’ ];” it works. But not from $resource.


like this:

.factory('Jobs', function($resource, $http) {
//  return $resource('http://www.mydomain.com/api/v1/jobs');
    
//  var jobs = [ 
//      { title: 'Systems Administrator', 'id': 0, min_salary: '1500', max_salary: '2000', city: 'Kota Bharu', state: 'Kelantan' },
//      { title: 'Computer Engineer', 'id': 1, min_salary: '1500', max_salary: '2000', city: 'Kota Bharu', state: 'Kelantan' },
//      { title: 'Network Engineer', 'id': 2, min_salary: '1500', max_salary: '2000', city: 'Kota Bharu', state: 'Kelantan' },
//      { title: 'Accountant', 'id': 3, min_salary: '1500', max_salary: '2000', city: 'Kota Bharu', state: 'Kelantan' },
//      { title: 'Promoter', 'id':4, min_salary: '1500', max_salary: '2000', city: 'Kota Bharu', state: 'Kelantan' },
//      { title: 'Systems Engineer', 'id': 5, min_salary: '1500', max_salary: '2000', city: 'Kota Bharu', state: 'Kelantan' }];
  var jobs = $resource('http://www.mydomain.com/api/v1/jobs');

  return {
    all: function() {
      return jobs;
    },
    get: function(jobId) {
      // Simple index lookup
      return jobs[jobId];
    }
  }
})

Many thanks!

When you’re working with ngResource, you can use MyResource.query(...).$promise.then(function(result){...}); and then do something with the results, like console.log(result); to see what results you’re getting back. Once you have a handle on that, you can go back to just assigning the MyResource.query() to a $scope variable

Also, I see the first line of your factory returns the $resource - did you mean to say var jobs = $resource(...

The first line that i wrote in my factory actually returns the data into ‘Jobs’ which is read my JobsCtrl. The .all method will show the data which is returned from the factory.

.controller('JobsCtrl', function($scope, Jobs, $http) {
  // Get all posts
  $scope.jobs = Jobs.all();
})

Ah, sorry, I was referring to the first, commented line; I missed the later definition. I’m a bit more awake now…

The $resource() function returns a resource object that you can then make REST calls with, such as query, get, put, etc. It doesn’t return the data itself. You would want to do one of these things I think:

In your service factory, if you’re only updating the jobs data when the service loads the first time:

var jobsResource = $resource('http://www.mydomain.com/api/v1/jobs');
jobs = jobsResource.query(...)

Note that jobs will only have a value once the resource request is complete. You might make a function on your service to update the jobs array with a new jobsResource.query(...) call.

Or, you can expose the jobsResource in your return statement, and call the appropriate methods from your controllers. This makes sure that the data is updated any time a controller calls a resource method, but also means that your service acts less like a service.

The examples in the docs aren’t exactly the clearest, but they do show how to set up a resource and call various methods. https://docs.angularjs.org/api/ngResource/service/$resource

I hope that’s more helpful :smile:

It is quite odd, once i select one of the items, it shows another item’s detail and only the first one works, the second, third and the rest did not. I think it might do with the jobId problem (index Id) but i am unsure.

.controller('JobsCtrl', function($scope, Jobs, $http) {
  // Get all posts
  $scope.jobs = Jobs.all();

  // Our form data for creating a new post with ng-model
  // $scope.postData = {};
  //$scope.newPost = function() {
  //  var post = new Post($scope.postData);
  //  post.$save();
  // }

  // Refresher
  $scope.doRefresh = function() {
    $http.get('http://www.mydomain.com/api/v1/jobs')
     .success(function(newJobs) {
       $scope.jobs = newJobs;
     })
     .finally(function() {
       // Stop the ion-refresher from spinning
       $scope.$broadcast('scroll.refreshComplete');
     });
  };

})

.controller('JobCtrl', function($scope, $stateParams, Jobs) {
  $scope.job = Jobs.get($stateParams.jobId);
});

When i use:

var jobs = [ 
      { title: 'Systems Administrator', 'id': 0, min_salary: '1500', max_salary: '2000', city: 'Kota Bharu', state: 'Kelantan' },
      { title: 'Computer Engineer', 'id': 1, min_salary: '1500', max_salary: '2000', city: 'Kota Bharu', state: 'Kelantan' }];

it works fine. Or can it be because of my JSON from the server? The Id doesn’t start with 0 and it random.

Thank you so very much for giving me the angular stuff… i will need it for some stuff.

EDIT
I found out that the code above in codepen uses an PlaylistId which is not random (starts with 0, then 1, 2, 3) but on the production the Id will be random and the code in the above codepen will not work under these circumstances.

ie:

var jobs = [ 
      { title: 'Systems Administrator', 'id': 2, min_salary: '1500', max_salary: '2000', city: 'Kota Bharu', state: 'Kelantan' },
    { title: 'Systems Administrator', 'id': 3, min_salary: '1500', max_salary: '2000', city: 'Kota Bharu', state: 'Kelantan' },
      { title: 'Computer Engineer', 'id': 9, min_salary: '1500', max_salary: '2000', city: 'Kota Bharu', state: 'Kelantan' }];

will have the data messed up.

That’s happening because the Javascript array jobs is indexed from 0, but your the id’s from the server are of course not, and thus are out of sync. I’d recommend using something like UnderscoreJS’s findWhere function - http://underscorejs.org/#findWhere. Although it’s less performant than an index lookup, you can use it to find an array element based on a key-value pair of that element’s properties. Your Jobs.get function would become something like

return _.findWhere(jobs, {id: jobId});

I have tried what you mentioned and the data is not being shown in the content view.

controller.js

.factory('Jobs', function($resource, $http) {
//  return $resource('http://gokerja.my/api/v1/jobs');
  var jobs = [
     { title: 'Systems Administrator', 'id':0, min_salary: '1500', max_salary: '2000', city: 'Kota Bharu', state: 'Kelantan', job_description: 'This is the job description' },
     { title: 'Computer Engineer', 'id':1, min_salary: '1500', max_salary: '2000', city: 'Kota Bharu', state: 'Kelantan', job_description: 'This is the job description' },
      { title: 'Network Engineer', 'id':2, min_salary: '1500', max_salary: '2000', city: 'Kota Bharu', state: 'Kelantan', job_description: 'This is the job description' },
      { title: 'Accountant', 'id':3, min_salary: '1500', max_salary: '2000', city: 'Kota Bharu', state: 'Kelantan', job_description: 'This is the job description' },
      { title: 'Promoter', 'id':4, min_salary: '1500', max_salary: '2000', city: 'Kota Bharu', state: 'Kelantan', job_description: 'This is the job description' },
      { title: 'Systems Engineer', 'id': 5, min_salary: '1500', max_salary: '2000', city: 'Kota Bharu', state: 'Kelantan', job_description: 'This is the job description' }];
//  var jobs = [];
//  var jobs = $resource('http://gokerja.my/api/v1/jobs');
//  jobsResource = $resource('http://gokerja.my/api/v1/jobs');
//  var jobs = jobsResource.query();

  return {
    all: function() {
      return jobs;
    },
    get: function(jobId) {
      // Simple index lookup
      // return jobs[jobId];
      return _.findWhere(jobs, {id: jobId});
    }
  }
})

index.html

<link href="lib/ionic/css/ionic.css" rel="stylesheet">
<link href="css/style.css" rel="stylesheet">

<!-- IF using Sass (run gulp sass first), then uncomment below and remove the CSS includes above
<link href="css/ionic.app.css" rel="stylesheet">
-->

<!-- ionic/angularjs js -->
<script src="lib/ionic/js/ionic.bundle.js"></script>

<!-- cordova script (this will be a 404 during development) -->
<script src="cordova.js"></script>

<!-- your app's js -->
<script src="js/app.js"></script>
<script src="js/controllers.js"></script>
<script src="lib/ionic/js/angular/angular-resource.min.js"></script>
<script src="lib/underscore/underscore.js"></script>

jobs.html

<ion-view view-title="Jobs">
  <ion-content>
   <ion-refresher
     pulling-text="Pull to refresh..."
     on-refresh="doRefresh()">
   </ion-refresher>
    <ion-list>
      <ion-item ng-repeat="job in jobs" ui-sref="app.job({jobId: job.id})" ui-sref-active="activated">
        <h2>{{job.title}}</h2>
        <p>{{job.city}}, {{job.state}}</p>
        <p>RM{{job.min_salary | number:0}} - RM{{job.max_salary | number:0}}</p>
      </ion-item>
    </ion-list>
  </ion-content>
</ion-view>

I did another way where i would ask the API again for the selected information.

.controller('JobCtrl', function($scope, $stateParams, $resource) {
  // $scope.job = Jobs.get($stateParams.jobId);
   jobResource = $resource('http://localhost.localdomain/api/v1/jobs/:id');
   $scope.job = jobResource.get({id: $stateParams.jobId})
});