7

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.

HTML Man
  • 937
  • 4
  • 16
  • 40
  • Take a look at ng-repeat: https://www.w3schools.com/angular/ng_ng-repeat.asp (I'm not a fan of official angular docs). – Daniel W. Nov 09 '17 at 22:58
  • Is that code in your question everything needed to run the problem? I only see HTML and some JSON. – Rob Nov 10 '17 at 00:46
  • @Rob yes I don't know angularjs too much and the list could be 100,000 or more – HTML Man Nov 10 '17 at 07:07
  • I don't see where you have provided any angular or javascript code at all. You are required to post a complete and minimal example of the problem code here. [mcve] – Rob Nov 10 '17 at 07:59
  • Much better. Do that every time. – Rob Nov 10 '17 at 20:48
  • Just use a directive. Pass each iterated element into the directive and output what you need in the directive template html (NewsViewer.html) – tymeJV Nov 13 '17 at 23:58
  • @HTMLMan did you checked my updated answer ? – Debug Diva Nov 17 '17 at 11:07

6 Answers6

3

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.

Steven J
  • 63
  • 7
2

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

Xavier Ñauñay
  • 309
  • 2
  • 5
  • 15
2

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.

31piy
  • 23,323
  • 6
  • 47
  • 67
2

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

Debug Diva
  • 26,058
  • 13
  • 70
  • 123
  • Please can you write your code in the plunker, or give more details as I dont know how to apply your solution – HTML Man Nov 14 '17 at 19:58
  • @HTMLMan I updated my answer with working plnkr. Thanks – Debug Diva Nov 15 '17 at 07:06
  • Well thanks for the demo but you use angular 1.2 and another one from github I don't know what is it. I cannot go for angular 1.2 either using the github that you used. – HTML Man Nov 18 '17 at 05:51
  • @HTMLMan I just used those for the demo. you can use `cdn` or `npm` to use those libraries in the project. – Debug Diva Nov 19 '17 at 03:04
-1

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>
hpatel
  • 199
  • 8
  • That will list all the JSON file. While I need to show one new depends on what is coming to newsviewer.html file – HTML Man Nov 13 '17 at 00:05
  • Then just remove the outer most foreach and supply a single Artical to the HTML based on route. – hpatel Nov 13 '17 at 01:01
-1

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.

Vipin Kumar
  • 6,441
  • 1
  • 19
  • 25
  • While this link may answer the question, it is better to include the essential parts of the answer here and provide the link for reference. Link-only answers can become invalid if the linked page changes. - [From Review](/review/low-quality-posts/17987723) – Mamun Nov 18 '17 at 07:57
  • I am new to stackoverflow, thanks for directing me. Let me know, if answer needs further modification. – Vipin Kumar Nov 18 '17 at 08:23