HTML Man
HTML Man

Reputation: 937

How to show a dynamic content in the same page using Angularjs 1.6?

I'm a newbie to Angular. I need to render a dynamic content from JSON file using AngularJS 1.6. Here is what I have.

News.json

   {
  "Articles": [
    {
      "Title": "News 1",    
      "Abstract": "News 1 abstract ...",
      "Body": "News 1 starts here.... ",
      "Comments": [
        {
          "comment 1" : "Comment 1 goes here",
          "comment 2" : "Comment 2 goes here",
          "comment 3" : "Comment 3 goes here"
        }]
    },

    {
      "Title": "News 2",
      "Abstract": "News 2 abstract ... ",
      "Body": "News 2 starts here...",
      "Comments": [
        {
          "comment 1" : "Comment 1 goes here",
          "comment 2" : "Comment 2 goes here"
        }]
    }    
  ]
}

Script.js

app.config(function ($routeProvider) {
    $routeProvider
        .when("/News", {
            templateUrl: "NewsViewer.html",
            controller: "showNews"
        });
});

app.controller("showNews", ["$scope", "$http", function ($scope, $http) {
    $http({
        method: 'GET',
        url: 'News/News.json'
    }).then(function success(data) {
        $scope.News = data.data;
    });
}]);

News.html

<div class="container-fluid">

    <div class="row">

        <div class="col-md-offset-1 col-md-6">
            <div ng-controller="NewsRendering">
                <div ng-repeat="NewsData in News.Articles">
                    <h3>{{NewsData.Title}}</h3>
                    <p>{{NewsData.Abstract}}</p>
                    <a data-ng-href="/AngularTask/NewsViewer.html">more</a>
                </div>
            </div>
        </div>

        <div class="col-md-4 questionnaire">
            <h3>Questionnaire of the day</h3>
        </div>

    </div>

</div>

NewsViewer.html

<div class="container-fluid">
    <div class="row">
        <div class="col-md-offset-1 col-md-6">
            <div ng-controller="showNews">
                <div>
                    <h3>{{News.Articles[0].Title}}</h3>
                    <p>{{News.Articles[0].Abstract}}</p>
                    <p>{{News.Articles[0].Body}}</p>
                </div>

                <div class="comments">
                    <h4>Comments</h4>
                    <hr>
                    <p>{{News.Articles[0].Comments[0]}}</p>
                </div>
            </div>
        </div>
    </div>
</div>

This code is working fine, but this code is not dynamic. My problem how to make it dynamic and can show whatever in json file. What should I do in JS code to pass the index of the array of the JSON File.

As you can see <h3>{{News.Articles[0].Title}}</h3> is showing only the first Title of the JSON file. I need to write it to be <h3>{{News.Articles[index of whatever].Title}}</h3>

Note: News.json has around 100,000 records. I make it two, just to show the code and describe the problem.

Upvotes: 7

Views: 2570

Answers (6)

Vipin Kumar
Vipin Kumar

Reputation: 6546

Please find the working solution below

https://embed.plnkr.co/rbNAcVGtBvTjl9VhfFAl/

Let me know, if you need further info. Enjoy :)

Edited

First of all we need to define two separate routes, one for News and one for Article

$routeProvider.when("/News", {
    templateUrl: "News.html",
    controller: "NewsContoller"
}).when("/NewsViewer", {
    templateUrl: "NewsViewer.html",
    controller: "NewsViewerController"
})

As you see, there are two separate controllers handling each route.

Then we need a value service to pass data between routes

angular.module('app').value('viewData', {})

After that on click of more link, set the value of viewData to that specific article and redirect to /NewsViewer route. And, on NewsViewerController retrieve that value from viewData and pass it to $scope.

Template: News.html

<div>
  <div ng-repeat="NewsData in News.Articles">
    <h3>{{NewsData.Title}}</h3>
    <p>{{NewsData.Abstract}}</p>
    <a href ng-click="showArticle(NewsData)">more</a>
  </div>
</div>

Template: NewsViewer.html

<div>
  <div>
    <h3>{{Article.Title}}</h3>
    <p>{{Article.Abstract}}</p>
    <p>{{Article.Body}}</p>
  </div>

  <div class="comments">
    <h4>Comments</h4>
    <hr>
    <p ng-repeat="(key, value) in Article.Comments[0]">
      {{value}}
    </p>
  </div>
</div>
<a ng-href="#!/News">All News</a>

Controller: NewsController

angular.module('app').controller('NewsContoller', function($scope, $http, viewData, $location) {
  $http({
    method: 'GET',
    url: 'News.json'
  }).then(function success(response) {
    $scope.News = response.data;
  });
  $scope.showArticle = function(article) {
    viewData.article = article;
    $location.path("/NewsViewer");
  }
})

Controller: NewsViewerController

angular.module('app').controller('NewsViewerController', function($scope, viewData) {
  $scope.Article = viewData.article;
})

Link of plunker is above in original answer.

Upvotes: -1

Roh&#236;t J&#237;ndal
Roh&#236;t J&#237;ndal

Reputation: 27222

Few observations as per your code :

  1. This line of code <a data-ng-href="/AngularTask/NewsViewer.html">more</a> will break the pupose of AngularJS which is Single page application (SPA).
  2. Use ui-router instead of ngRoute to get better as ngRoute is outdated.
  3. Instead of redirecting a user to a html template (/AngularTask/NewsViewer.html) directly, change the state of the view using ui-sref with params and pass the $index as param value.

Try below approach to get result as per the expectation :

News.html

  <div ng-repeat="NewsData in News.Articles">
    <h3>{{NewsData.Title}}</h3>
    <p>{{NewsData.Abstract}}</p>
    <a href="javascript:void(0)" ui-sref="newsdetails({index: $index})">more</a>
  </div>

routes.js :

$stateProvider
    .state('newsdetails', {
      url: '/news-details/:index',
      controller: 'showNews',
      templateUrl: 'NewsViewer.html'
    })
    ....

Controller :

.controller('showNews', function($scope, $stateParams) {
    $scope.indexVal = $stateParams.index; // getting index value passed from news.html
});

NewsViewer.html :

 <div ng-controller="showNews">
     <div>
         <h3>{{News.Articles[indexVal].Title}}</h3>
         <p>{{News.Articles[indexVal].Abstract}}</p>
         <p>{{News.Articles[indexVal].Body}}</p>
     </div>
 </div>

Working demo : https://plnkr.co/edit/jfzm00ksZMAC8sGGUZSR?p=preview

Upvotes: 2

Steven J
Steven J

Reputation: 63

I think what you need is using 'ng-repeat' to show the Array Articles and '$http.get()' to load the json.file "dynamically" as you want.

Upvotes: 3

31piy
31piy

Reputation: 23859

You can do it by passing the index of the news to the /News route.

First, change News.html so it tracks the data by index, and then appends the index of the item to the ng-href.

<div ng-repeat="NewsData in News.Articles track by $index">
  <h3>{{NewsData.Title}}</h3>
  <p>{{NewsData.Abstract}}</p>
  <a data-ng-href="/AngularTask/NewsViewer.html?index={{$index}}">more</a>
</div>

Now, for each visit, you will see a new query parameter in the NewsViewer route, which will be index.

Second, change the controller, so it takes the advantage of passed index using $routeParams.

app.controller("showNews", ["$scope", "$http", "$routeParams",
  function ($scope, $http, $routeParams) {
    $http({
        method: 'GET',
        url: 'News/News.json'
    }).then(function success(data) {
        $scope.News = data.data.Articles[$routeParams.index];
    });
}]);

This way, $scope.News will contain the article which resides on the passed index.

Finally, change NewsViewer.html so that it uses $scope.News.

<div class="container-fluid">
    <div class="row">
        <div class="col-md-offset-1 col-md-6">
            <div ng-controller="showNews">
                <div>
                    <h3>{{News.Title}}</h3>
                    <p>{{News.Abstract}}</p>
                    <p>{{News.Body}}</p>
                </div>

                <div class="comments">
                    <h4>Comments</h4>
                    <hr>
                    <p>{{News.Comments[0]}}</p>
                </div>
            </div>
        </div>
    </div>
</div>

For comments, you can again use ng-repeat directive to show all the comments, iterating over them one-by-one.

Hope this answers your question.

Upvotes: 2

hpatel
hpatel

Reputation: 199

I think this is what you want

NewsViewer.html

        <div class="container-fluid">
    <div class="row">
        <div class="col-md-offset-1 col-md-6">
            <div ng-controller="showNews">
                <div>
                    <div>
                        <h3>{{selectedArticle.Title}}</h3>
                        <p>{{selectedArticle.Abstract}}</p>
                        <p>{{selectedArticle.Body}}</p>
                    </div>

                    <div class="comments">
                        <h4>Comments</h4>
                        <hr>
                        <div ng-repeat="comment in selectedArticle.Comments">
                            <p ng-repeat="(key, value) in comment">
                                <strong>{{key}}</strong>: {{value}}
                            </p>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>

Upvotes: -1

You need to use a routing service in combination with the rootScope to save the selected object. I made an easy example for you:

angular
.module('myApp', ['ngRoute'])
.config(['$routeProvider', function($routeProvider){
    $routeProvider
        .when('/list', {
            templateUrl: 'pages/list.html',
            controller: 'listController'
        })
        .when('/details', {
            templateUrl : 'pages/details.html',
            controller: 'displayController'
        })
        .otherwise({redirectTo: '/list'});
}])
.controller('listController', function($scope, $rootScope) {
    var myObject = {
        Listoflinks: [{
            "Title": "Link 1",
            "Abstract": "abstract is here ....",
            "Body": "Body is here ...",
        },
        {
            "Title": "Link 1",
            "Abstract": "abstract is here ....",
            "Body": "Body is here ...",
        }]
    }
    $rootScope.detail = myObject.Listoflinks[0];
})
.controller('displayController', function($scope, $rootScope) {
    $scope.detail = $rootScope.detail;
});

https://plnkr.co/edit/0SYnFcjlgGyTowlcpvgz?p=catalogue

Upvotes: 2

Related Questions