2

first and foremost, this is my first encouter with Angular.

What I am aiming to achieve is, I have a list of notifications, that I somehow must limit with limitTo, so the elements are limited to three and after I click the button, the rest should load up.

What I dont understand how to do:

  • set up the "view" and how to apply ng-repeat
  • load the JSON data that I have set up and somehow parse it as pure HTML from the *json into the view
  • after everything goes well, use limitTo so I Can limit the items to 3 from the start and after I click the button, I want the rest to load under.

I request assistance, this is as far as I've come.

Sample code because SO requires it:

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

app.controller('mainController', function($scope, $http) {

$http({
    method: 'GET',
    url: 'notifications.json'
}).success(function(){
    console.log('success');
}).error(function(){
    console.log('error');
});

$scope.loadmore = true;
});

Here is a Plunker

Thank You in advance!

Tanasos
  • 3,928
  • 4
  • 33
  • 63
  • Have you completed the tutorial at the angularjs site? It pretty much demonstrates how to do all of this, including how to use ngAnimate. – Amy Blankenship May 16 '16 at 20:13

7 Answers7

1

Your plunker has a couple of errors.

First of all, your ng-app in index.html should be notifyApp, since that's what you've set in your script.js - var app = angular.module('notifyApp', []);

Secondly: you have to assign your notifications to $scope.notifications in your success function.

$http({
    method: 'GET',
    url: 'notifications.json'
}).then(function(res){
    $scope.notifications = res;
});

After that you should already see the first 3 elements.

Last thing you need is to remove notifications = !notifications from the load more button's ng-click attr.

Modified Plunker here.

John Smith
  • 2,291
  • 4
  • 22
  • 33
  • This clears things out. This is close to what I tried to do earlier, but in this case it works. Thank You very much! – Tanasos May 16 '16 at 19:08
1

Setting up the view and using ng-repeat.

You'll want to store the notifications somewhere (probably an array) and then use ng-repeat="data in yourArray" in your html file within a tag (div for example). You can then apply filters to it if you want to show specific notifications. In your case, you want to initially show 3 and then move onto the rest if a button is clicked. You could create a separate array that stores the first 3 notifications and and another that contains the whole array and use ng-if in your tag to display the results.

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

myApp.controller('notificationController', ['$scope',
  function($scope) {
    $scope.buttonNotClicked = true;

    $scope.fullArray = [item1, item2, item3, item4, item5];
    $scope.partialArray = [fullArray[0], fullArray[1], fullArray[2]];


    function onButtonClick() {
      $scope.buttonNotClicked = false;
    }
  }
]);
<div ng-if="buttonNotClicked">
  <div ng-repeat="data in partialArray"></div>
</div>

<div ng-if="!buttonNotClicked">
  <div ng-repeat="data in fullArray"></div>
</div>

How to use parameters within the filter in AngularJS?

Community
  • 1
  • 1
Jeff L
  • 141
  • 2
  • 12
1

So the first step is that on the success callback you should save then returning data somewhere in your scope, like:

.success(function (data) {

   $scope.myList = data;

   $scope.myListLimit = 3; // lets also set a limit for our list
}

Then, you can write your view as descendant of the element that points to the ng-controller directive:

<div ng-controller="mainController">
  <ul ng-repeat="item in myList | limitTo: myListLimit">
    <li>{{item}}</li>
  </ul>
  <button type="button" ng-show="anyResultsPending()" ng-click="showMoreResults()">Show more results</button>
</div>

After that your list should be shown with 3 results, and to be able to show more as a result of the user interaction, we create a new method on the controller:

$scope.showMoreResults = function () {

   $scope.myListLimit += 3;
}

// this is to hide the "show more results" button after the all items was shown
$scope.anyResultsPending = function () {

   return $scope.myList && $scope.myListLimit < $scope.myList.length; 
}
1

In addition, as explained in AngularJS : Insert HTML into view , when using HTML contained in JSON, you need to Sanitize. Use this module:

<script src="bower_components/angular-sanitize/angular-sanitize.js"></script>

In your JS, I was surprised, it seems to be as simple as adding a dependency:

  var ricksiteControllers = angular.module('ricksiteControllers', ["ngSanitize"]);

  ricksiteControllers.controller('PagesCtrl', ['$scope', 'Page',
          function($scope, Page) {
              $scope.pages = Page.query();
  }]);

And my services.js has the angular-resource code:

var ricksiteServices = angular.module('ricksiteServices', ['ngResource']);

ricksiteServices.factory('Page', ['$resource',
  function($resource){
    return $resource('pages/:pageId.json', {}, {
      query: {method:'GET', params:{pageId:'pages'}, isArray:true}
    });
  }]);
// actually, the pageID parameter has only one value, only the default 'pages' is used.
Community
  • 1
  • 1
rleir
  • 791
  • 1
  • 7
  • 19
  • I tried using it earlier, but I didn't got much success with it. What do I need to do in order for it to work? Add it as a dependancy in the module , [ ] ? – Tanasos May 16 '16 at 19:17
  • 1
    The answer is now updated to show the JS. Suspiciously simple. – rleir May 16 '16 at 19:43
  • In my case: var app = angular.module('notifications', ["ngSanitize"]); followed by the second .controller snippet , but doesn't seem to work. Where did I went terribly wrong? – Tanasos May 16 '16 at 19:48
  • 1
    Is that code in your plnker? I did not see it. Maybe the diff is in my use of services, as will be added to the JS in a moment. – rleir May 16 '16 at 19:54
  • 1
    I wrote this code while looking at the tutorial for ng 1.5 – rleir May 16 '16 at 20:01
1

Here's a solution that does what some other answers don't provide:

  • Animation
  • Loads objects directly from your JSON using an angular factory and promises
  • Limits to 3 items and loads the rest on a button click

JavaScript:

(function () {
    "use strict";

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

    module.factory('NotificationsService', ['$http', function ($http) {
        return {
            fetch: function () {
                return $http.get('notifications.json').then(function (response) {
                    return response.data
                });
            }
        };
    }]);

    module.controller('Controller', ['$scope', '$filter', 'NotificationsService', function ($scope, $filter, NotificationsService) {
        $scope.notifications = [];
        $scope.limit = 3;
        $scope.allLoaded = false;

        NotificationsService.fetch().then(function (data) {
            $scope.notifications = data;
        });

        $scope.loadAll = function () {
            $scope.limit = $scope.notifications.length;
            $scope.allLoaded = true;
        };
    }]);
})();

Html/CSS

<!doctype html>
<html ng-app="app">

<head>
    <title>ng-limit</title>

    <style>
        .my-repeat-animation.ng-enter,
        .my-repeat-animation.ng-leave,
        .my-repeat-animation.ng-move {
            -webkit-transition: 0.5s linear all;
            transition: 0.5s linear all;
            position: relative;
        }

        .my-repeat-animation.ng-enter {
            top: -20px;
            opacity: 0;
        }

        .my-repeat-animation.ng-enter.ng-enter-active {
            top: 0;
            opacity: 1;
        }

        .my-repeat-animation.ng-leave {
            top: 0;
            opacity: 1;
        }

        .my-repeat-animation.ng-leave.ng-leave-active {
            top: -20px;
            opacity: 0;
        }

        .my-repeat-animation.ng-move {
            opacity: 0.5;
        }

        .my-repeat-animation.ng-move.ng-move-active {
            opacity: 1;
        }
    </style>

    <script src="node_modules/angular/angular.js"></script>
    <script src="node_modules/angular-animate/angular-animate.js"></script>
    <script src="app.js"></script>
</head>

<body ng-controller="Controller">
    <button ng-show="!allLoaded" ng-click="loadAll()">Load all</button>
    <div ng-repeat="notification in notifications | limitTo:limit" class="my-repeat-animation">
        <div>
            <h4>Notification: {{$index+1}}</h4>
            <div>
                Avatar: {{notification.avatar}}
            </div>
            <div>
                Type: {{notification.type}}
            </div>
            <div>
                Name: {{notification.userName}}
            </div>
            <div>
                Action: {{notification.userAction}}
            </div>
            <div>
                Target: {{notification.targetObject}}
            </div>
        </div>
    </div>
</body>

</html>
mariocatch
  • 8,305
  • 8
  • 50
  • 71
0

I've got a solution. Try it in your plnkr.

Note how I've hardcoded $scope.notifications. You'll want to retrieve the actual data - can't figure out how to do it in plnkr. When you do retrieve the JSON, you will have to trust the data like so:

var app = angular.module('notifications', []);
app.controller('mainController', function($scope, $http, $sce) {
   $http({
        method: 'GET',
        url: 'notifications.json'
    }).success(function(data){
        console.log('success');
        $scope.notifications = data;
        for (var i=0; i<$scope.notifications.length; i++){
             $scope.notifications[i].userAction = $sce.trustAsHtml($scope.notifications[i].userAction)
        }
    }).error(function(data){
        console.log('error');
    });
    $scope.myLimit = 3;

    $scope.loadmore = true;
});

EDIT because perhaps explanations are due. Here are the changes I made:

  • Angular Module had an error (wrong name) so I changed the first line of JS.
  • $scope.notifications must be declared in the JS.
  • Added $scope.myLimit so we can modify this variable for limitTo
  • In ng-click, removed notifications = !notifications, added myLimit = notifications.length so it can show all results.
  • Finally, added ng-bind-html instead of {{notification.userAction}} so it can be displayed as HTML.

JS:

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

app.controller('mainController', function($scope, $http) {

$http({
    method: 'GET',
    url: 'notifications.json'
}).success(function(){
    console.log('success');
}).error(function(){
    console.log('error');
});

$scope.notifications = [
{
    "avatar" : "images/otherUser.png",
    "type" : "",
    "userName" : "Ivana Stankova",
    "userAction" : "<span class=\"heart\">&#10084;</span>&nbsp;your photo",
    "targetObject" : "images/targetPhoto.jpg"
},
{
    "avatar" : "images/otherUser2.png",
    "type" : "",
    "userName" : "Ivana Stankova",
    "userAction" : "<span class=\"heart\">&#10084;</span>&nbsp;your photo",
    "targetObject" : "images/targetPhoto.jpg"
},
{
    "avatar" : "images/otherUser4.png",
    "type" : "checkedIn",
    "userName" : "Dave Peters",
    "userAction" : "Checked in<br/><a href=\"#\">962 Grant Street Victoria</a>",
    "targetObject" : "images/place.jpg"
},
{
    "avatar" : "images/otherUser4.png",
    "type" : "commented",
    "userName" : "Dave Peters",
    "userAction" : "Commented on <a href=\"#\">your post</a><p>Hey guys,&nbsp8 o’clock? Let’s get some food first? How<br/>about that fancy restaurant we wanted to try for...</p>",
    "targetObject" : "images/targetPhoto.jpg"
},
{
    "avatar" : "images/otherUser.png",
    "type" : "",
    "userName" : "Ivana Stankova",
    "userAction" : "<span class=\"heart\">&#10084;</span>&nbsp;your photo",
    "targetObject" : "images/targetPhoto.jpg"
},
{
    "avatar" : "images/otherUser.png",
    "type" : "",
    "userName" : "Ivana Stankova",
    "userAction" : "<span class=\"heart\">&#10084;</span>&nbsp;your photo",
    "targetObject" : "images/targetPhoto.jpg"
},
{
    "avatar" : "images/otherUser4.png",
    "type" : "",
    "userName" : "Dave Peters",
    "userAction" : "<a href=\"#\">Made a new post.</a>",
    "targetObject" : "images/targetPhoto.jpg"
},
{
    "avatar" : "images/otherUser.png",
    "type" : "",
    "userName" : "Ivana Stankova",
    "userAction" : "Started following you.",
    "targetObject" : ""
},
{
    "avatar" : "images/fivePeople.png",
    "type" : "",
    "userName" : "",
    "userAction" : "Five people Started following You.",
    "targetObject" : ""
}
]

$scope.myLimit = 3;

    $scope.loadmore = true;
});

Index.html

<!DOCTYPE html>
<html lang="en" ng-app="notifications">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>App</title>
    <link rel="stylesheet" href="style.css">
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.9/angular.min.js"></script>
    <script src="script.js"></script>
</head>
<body class="container" ng-controller="mainController">
    <header>
        <a id="logo" href="www.google.com"><img src="images/logo.png" alt="logo"></a>
        <nav id="menu">
            <ul>
                <li><a href="#"><img src="images/bell.png" alt="bell icon"></a></li>
                <li>
                    <a href="#">
                        <img src="images/message.png" alt="message icon">
                        <div id="nCount">22</div>
                    </a>
                </li>
                <li><a href="#"><img src="images/profilePic.png" alt="girl profile pic"></a></li>
            </ul>
        </nav>
    </header>
    <main>
        <div class="wrapper">
            <div id="list">
                <h1>My notifications</h1>
                <ul id="mainList" ng-show="notifications" class="slideInDown" ng-init="limit = myLimit">
                    <li ng-repeat="notification in notifications | limitTo: limit">
                        <figure>
                            <img src="{{notification.avatar}}" alt="other user photo">
                        </figure>

                        <div class="infoLine {{notification.type}}">
                            <a class="userName" href="#">{{notification.userName}}</a>
                            &nbsp;<span ng-bind-html="notification.userAction"></span>
                        </div>

                        <div class="whenWhat">
                            <span>
                                <img src="images/clock.png" alt="clock illustration">
                                2m
                            </span>
                            <img src="{{notification.targetObject}}" alt="photo">
                        </div>
                    </li>
                </ul>
            </div>
            <a id="loadMore" href="#" ng-show="loadmore" ng-click=" loadmore = false ; limit = notifications.length; myLimit = notifications.length" ng-class="{ active: notifications }" >Load More</a>
        </div>
    </main>
</body>
</html>
chakeda
  • 1,551
  • 1
  • 18
  • 40
  • 2
    Someone downvoted another solution as well. As a tradition I give an upvote to all participants. Wasn't me. – Tanasos May 16 '16 at 19:05
  • Any idea how can I use ngAnimate so that I can animate each of them while appearing with ng-repeat, or should I just stick to css animation? – Tanasos May 16 '16 at 19:05
  • 1
    @chakeda My wild guess would be other solutions has better explanations, more details. – Andrew May 16 '16 at 19:06
  • Should I be using the ng-sanitize module? The ng-bind-html seems to be working fine? – Tanasos May 16 '16 at 19:18
  • 1
    @Sqnkov See my edited answer. When you get the JSON from say, an API, you will have to `$sce.trustAsHtml` the data. I'd recommend creating a new question for the ng-animate. – chakeda May 16 '16 at 19:23
  • Your main edit up top, it seems I can't get it up and running on my local server. My *.js file contains your "JS:" snippet without the hardcoded array, and I have added Your latest edit, the snippet on the top of the comment. – Tanasos May 16 '16 at 19:38
  • 1
    @Sqnkov Edited again. The main edit up top should work copy pasted into script.js. – chakeda May 16 '16 at 19:55
  • @chakeda , this is straight to the point! But now it spits it out as raw string, with the html tags along it. – Tanasos May 16 '16 at 19:58
  • 1
    @Sqnkov Hmm are you getting an error in the console? – chakeda May 16 '16 at 20:14
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/112083/discussion-between-sqnkov-and-chakeda). – Tanasos May 16 '16 at 20:15
0

First of all, you should use then() promisse instead success() and error(). This is the current way that promisses should be used.

You can limit your nrRepeat looping using ´limitTo=val´ in your ng-repeat attribute.

I made a snippet to show you a solution for your problem:

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

myApp.controller('myAppController', ['$scope', function($scope){
  $scope.defaultLimit = 3; // the default limit
  $scope.list = ['item 1', 'item 2', 'item 3', 'item 4', 'item 5', 'item 6', 'item 7'];
  $scope.showAll = function(){
    $scope.defaultLimit = $scope.list.length; // show all reccords
  }  
}]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>

<div ng-app="myApp">
  <div ng-controller="myAppController">
    <ul>
      <li ng-repeat="item in list | limitTo:defaultLimit">{{item}}</li>
    </ul>
    <button ng-click="showAll()" type="button">Show all</button>
  </div>
</div>
Bruno João
  • 5,105
  • 2
  • 21
  • 26
  • So you are creating a scope, which is assigned to the json list and you append "length" to it, that is another way to do it. Mine was unecessary complex right? I don't fully understand it though, I found it somewhere in Google. – Tanasos May 16 '16 at 18:57
  • 1
    I wouldn't say yours was unnecessary complex, rather a bit buggy. It's more like a matter of preference if anything. – John Smith May 16 '16 at 19:09
  • 1
    The point here is the ´$scope.defaultLimit´ variable that is used to limit the ng-repeat. Its default value is 3 as you want. what I do is change this variable assignin the array length to it, so your limit will be the entire array. – Bruno João May 16 '16 at 19:34