Creating a 'More posts...' button in Angular.js - angularjs

I am currently trying to make a 'show posts' button, for my Angular.js app. I am having trouble in setting the limitTo dynamically from an external script. So far I have:
<body ng-controller="FeedCtrl">
<h1>Feeds</h1>
<div ng-repeat="feed in (feedLoader = (feeds | limitTo:5))">
<p>{{feed.content}}</p>
</div>
<button ng-click="showPosts()">Show more...</button>
</body>
The approach I have taken is this:
$scope.showMorePosts = function () {
$scope.feedLoader = (feeds | limitTo:feedLimit);
}
...then replaced limitTo:5 with limitTo:feedLimit in the inline part of the view.
I have set up a Plunker with the basic setup so far here: http://plnkr.co/edit/OFqkGFKVUHKi2A20c4t3
Any help would be great!
Thanks,
JP

Seems like you were on the right track, but you just needed to define showPosts():
$scope.showMore = function() {
$scope.feedLimit += 1;
}
Full example:
http://plnkr.co/edit/pE49Wt0rvDjWhsKD0WiD?p=preview
HTML
<div ng-repeat="feed in (feedLoader = (feeds | limitTo:feedLimit))">
<p>{{feed.content}}</p>
</div>
<button ng-click="feedLimit = feedLimit + 1">Show more...</button>
JavaScript:
app.controller('FeedCtrl', function($scope) {
$scope.feedLimit = 3;
// ...
});

Related

How to drag particular div on ng repeat in angularjs

I am preparing charts on repeat.
I have applied drag properties to <div>, I am able to drag the div element but if multiple charts are added to that div on ng-repeat it is misbehaving, with only the first div dragging if I drag any other chart.
This is my code (I am using Dev Extreme to prepare charts using Angularjs)
<div style="background-color:white;" id="myElement" dx-dragenter="dragEnter($event)" dx-dragleave="dragLeave($event)" >
<div ng-repeat="chart in FinalPieData" id="innerElement" dx-drag="dragged($event)" dx-dragstart="dragStarted($event)" dx-dragend="dragStopped($event)">
<div class="col-lg-6" ng-repeat="pie in chart" ng-mouseleave="HideTitlePieOnLeave()">
<div id="ibtMulPie" class="ibox float-e-margins">
<div ng-mouseover="ShowTitlePie(pie)">
<div class="demo-container">
<div id="pie" dx-pie-chart="pie"></div>
</div>
</div>
</div>
</div>
</div>
</div>
drag code JS
//pie
$scope.dragStarted = function () {
$("#innerElement").css("background-color", draggedColor);
initialTop = parseInt($("#innerElement").css("top"));
initialLeft = parseInt($("#innerElement").css("left"));
initialPointerY = arguments[0].clientY;
initialPointerX = arguments[0].clientX;
};
$scope.dragged = function () {
$("#innerElement").css("top", initialTop + arguments[0].clientY - initialPointerY);
$("#innerElement").css("left", initialLeft + arguments[0].clientX - initialPointerX);
};
$scope.dragStopped = function () {
$("#innerElement").css("background-color", "green");
};
$scope.dragEnter = function () {
draggedColor = "red";
$("#innerElement").css("background-color", draggedColor);
};
$scope.dragLeave = function () {
draggedColor = "yellow";
$("#innerElement").css("background-color", draggedColor);
};
The repeated divs all have the same id.
You can make all id's unique like so:
ng-repeat="chart in FinalPieData track by $index" id="innerElement{{$index}}"
Now you can fetch the element using the event that you pass into the drag functions, or pass the id in as well and use that in your selector like so:
In html
dx-dragstart="dragStarted($event, $index)"
And in controller
$scope.dragStarted = function (event, index) {
var elementid = "#innerElement" + index;
$(elementid).css("background-color", draggedColor);
initialTop = parseInt($(elementid).css("top"));
initialLeft = parseInt($(elementid).css("left"));
initialPointerY = arguments[0].clientY;
initialPointerX = arguments[0].clientX;
};

Angular: How do I compile once then destroy all watches?

Due to performance issue, I would like to be able to simply compile a template piece once, then completely remove all watches etc from it, simply use the final template for display purpose only.
I tried with $compile but as soon as I use $destroy on scope then everything including the parsed content is reversed back to default.
Note: this is regarding Angularjs 1.5, not Angular 2
-----Edit 1------
#Stepan Kasyanenko suggested I can use one-way binding. I'm actually using it but with some issues:
I have thousands of form rows I need to display and angularjs cannot handle this amount of watches, so I decided to cheat by printing a display version of these rows only. Whenever the user clicks on a row to edit then I swap it out with a real editable model.
For these display only rows I'm using one-way binding.
It would be great if I can skip the one-way binding as well since it still creates some performance issue though much less than ngModel, that's why I asked the question.
With one-way binding, it seems like for some reason, even with the same code on the different sites behavior is flaky. Sometimes the live model is updated with 1 long text when the user types something, but the display version only get the 1st text (probably because of the way one-way binding should works. The only solution I can think of is to re-compile the display row at this time?
You can use one-way binding.
For example jsfiddle:
angular.module('ExampleApp', [])
.controller('ExampleController', function($scope) {
$scope.oneWay = "one";
$scope.twoWay = "two";
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.8/angular.js"></script>
<div ng-app="ExampleApp">
<div ng-controller="ExampleController">
<div> One way
<input ng-model="oneWay"> {{::oneWay}}
</div>
<div> Two way
<input ng-model="twoWay"> {{twoWay}}
</div>
</div>
</div>
UPDATE
I did some comparisons for drawing large amounts of data.
Example on jsfiddle
AngularJs v1.4.8. With one-way binding. 100k records - 7 sec on script, 7 second on render.
jQuery v2.2.3. 100k records - 8 sec on script, 6 second on render. Results may be better. It is necessary to pass a separate examination.
Native JS. 100k records - 0.3 sec on script, 6 second on render.
As you can see the fastest way - the Native JS.
angular.module('ExampleApp', [])
.controller('ExampleController', function() {
var vm = this;
vm.countRow = 100000;
vm.arrayAngular = [];
vm.startGenerateAngular = function() {
vm.arrayAngular = [];
for (var i = 0; i < vm.countRow; i++) {
vm.arrayAngular.push(i);
}
}
});
function startGenerateJQuery() {
var count = $("#countRow").val() * 1;
var $content = $("#contentJQuery");
$content.html("");
for (var i = 0; i < count; i++) {
var divParent = $('<div>');
var divChild = $('<div>');
divChild.text(i);
divParent.append(divChild);
$content.append(divParent);
}
}
function startGenerateNative() {
var count = $("#countRow").val() * 1;
var content = document.querySelector("#contentNative");
content.innerHTML = "";
for (var i = 0; i < count; i++) {
var divParent = document.createElement('div');
var divChild = document.createElement('div');
divChild.innerText = i;
divParent.appendChild(divChild);
content.appendChild(divParent);
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.3/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<div ng-app="ExampleApp">
<div ng-controller="ExampleController as vm">
<input id="countRow" ng-model="vm.countRow">
<div>Generate angular: 100k records - 7 sec on script, 7 second on render
<br>
<input type="button" ng-click="vm.startGenerateAngular()" value="Go">
</div>
<div>Generate jQuery: 100k records - 8 sec on script, 6 second on render
<br>
<input type="button" onclick="startGenerateJQuery()" value="Go">
</div>
<div>Generate Native: 100k records - 0.3 sec on script, 6 second on render
<br>
<input type="button" onclick="startGenerateNative()" value="Go">
</div>
<div ng-repeat="item in vm.arrayAngular">
<div>{{::item}}</div>
</div>
<div id="contentJQuery">
</div>
<div id="contentNative">
</div>
</div>
</div>

dynamically change options in dropdown list in angular js

i tried to create dynamically changing dropdown list in angularJS
angulars.js
var option1Options = ["Class","Category","Option","Question","Group"];
var option2Options = [["Group","ProductModel"],
["Class","ProductModel"],
["Class","Group","ProductModel"],
["Group","ProductModel"],
["ProductModel"]];
$scope.myCtrl= function()
{
$scope.options1 = option1Options;
$scope.options2 = [];
$scope.getOptions2 = function(){
var key = $scope.options1.indexOf($scope.child);
$scope.options2 = option2Options[2];
};
}
page.html
<div id="CreateChild" ng-controller="myCtrl">
<select ng-model="child" ng-options="option for option in options1" ng-change="getOptions2()">
</select>
<select ng-model="parent" ng-options="option for option in options2">
</select>
</div>
in angulars.js i was unable to get the index of first dropdown list array. the value of key is assigned as -1 and the option2 is assigned as undefined.
can any one help me with this
I did a small workaround for this requirement, though it is not a straight answer, I believe this would help you...
Add this to your controller...
$scope.getOptions1Idx = function(){
var mySelectedOption = $scope.child;
var i = 0;
for(i=0;i< option1Options.length;i++){
if(option1Options[i]==mySelectedOption){
break;
}
}
return i;
}
and change your getOptions2 function as follows
$scope.getOptions2 = function(){
$scope.options2 = option2Options[getOptions1Idx()];
};
This can be done in much better fashion by avoiding for loop provided if you choose to change your array structure with predefined index some thing like var option1Options = [{id:0,option:"Class"},{id:1,option:"Category"},{id:2,option:"Option"},{id:3,option:"Question","Group"}];
Had a very similar problem with this. In terms of styling I found my way around it by creating a list instead of a select option
<div class='btn-group'>
<button class='form-control col-md-3' data-toggle='dropdown'>
{{value}} <span class='caret'></span>
</button>
<ul class='dropdown-menu'>
<li ng-repeat='type in callType' class='col-md-3'>
<a href='#' ng-click='select(type)'>{{type.name}}</a>
</li>
</ul>
</div>
Then the controller is used to take in the objects, call a method to change each object and then set a default for the drop down list. You can see it at the link below.
http://plnkr.co/edit/nwXmMif8vjj92pQmalb2

How Do I Move Objects Inside An ng-Repeat on Button Click?

I have a nifty list of items in an ng-repeat with an up and down button on each. I just want the up button to move the list item up one place and the down button should move it down one place.
The problem is that I get an error saying "Cannot read property 'NaN' of undefined."
It seems "position" is undefined on the second line. What can I do to fix that?
Heres the javascript I'm working with (thanks to Rishul Matta):
$scope.moveUp = function(ind, position) {
$scope.temp = $scope.list[position - 1];
$scope.list[position - 1] = $scope.list[position];
$scope.list[position = temp];
};
Here's my HTML:
<ul>
<li class="steps" ng-repeat="step in selectedWorkflow.Steps track by $index" ng-class="{'words' : step.Id != selectedStep.Id, 'selectedWords' : step.Id == selectedStep.Id}" ng-model="selectedWorkflow.Step" ng-click="selectStep(step, $index); toggleShow('showSubStep'); toggleShow('showEditBtn')">
{{step.Name}}
<input class="orderUpBtn" type="button" ng-click="moveUp($index, step)" style="z-index:50" value="U" />
<input class="orderDownBtn" type="button" style="z-index:50" value="D" />
</li>
</ul>
Thanks!
Thanks for posting this question (+1) and the answer jtrussell (+1). I wanted to share what I believe to be a more re-usable/modular answer for other folks (inspired by odetocode.com post).
For the HTML, jtrussell's code is perfect because he fixed/simplified everything. For a better user experience I just added ng-disabled for the first/last elements.
HTML:
<ul ng-controller="DemoCtrl as demo">
<li ng-repeat="item in demo.list">
{{item}}
<button class="move-up"
ng-click="listItemUp($index)"
ng-disabled="$first">
Move Up
</button>
<button class="move-down"
ng-click="listItemDown($index)"
ng-disabled="$last">
Move Down
</button>
</li>
</ul>
For the JS, Notice the moveItem() function which I believe to be more re-usable. You can use this function for other drag+drop swapping functionality as well.
JS within Controller (tested on Angular 1.3.15):
// Move list items up or down or swap
$scope.moveItem = function (origin, destination) {
var temp = $scope.list[destination];
$scope.list[destination] = $scope.list[origin];
$scope.list[origin] = temp;
};
// Move list item Up
$scope.listItemUp = function (itemIndex) {
$scope.moveItem(itemIndex, itemIndex - 1);
};
// Move list item Down
$scope.listItemDown = function (itemIndex) {
$scope.moveItem(itemIndex, itemIndex + 1);
};
I hope it is helpful to someone out there. Thanks SO community!
A simple list with up/down buttons is pretty straightforward, here's some rough generic code. The ngRepeat directive will honor the order of items in your array so moving things around the view is just a matter of moving them in the array itself.
view:
<ul ng-controller="DemoCtrl as demo">
<li ng-repeat="item in demo.list">
{{item}}
<button ng-click="demo.moveUp($index)">up</button>
<button ng-click="demo.moveDown($index)">down</button>
</li>
</ul>
controller:
app.controller('DemoCtrl', function() {
this.list = list = ['one', 'two', 'three', 'four'];
this.moveUp = function(ix) {
if(ix > -1 && ix < list.length - 1) {
var tmp = list[ix+1];
list[ix+1] = list[ix];
list[ix] = tmp;
}
};
this.moveDown = function(ix) {
// similar...
};
});
There were a few strange items in your code (for example did you mean $scope.list[position] = temp; when you wrote ($scope.list[position = temp];), my example isn't perfect but it should get you going on the right path. Here's the full working demo: http://jsbin.com/vatekodeje, note that in my code I use "up" to mean increasing index rather than toward the top of the page.
Also in your controller you use position as an index (it's not clear that it should be) and make reference to, presumably, an array called $scope.list when in your view you use selectedWorkflow.Steps. Maybe your $scope.list and selectedWorkflow.Steps are meant to be the same thing?

Angularjs - Pagination appear after search filter

I am newbie on AngularJS.
Search result can be displayed in one page but why the next and previous button is showing ?
http://jsfiddle.net/2ZzZB/1473/
<input type="text" id="txtNotessearch" ng-model="search_notes" class="form-control input-sm" placeholder="SEARCH">
...
<ul>
<li ng-repeat="item in data | filter:search_notes | startFrom:currentPage*pageSize | limitTo:pageSize">
{{item}}
</li>
</ul>
Correct me, if I am wrong.
Because NumberOfPages is not filtered.
Instead of using $scope.data.length, you should use the length after the filter.
function MyCtrl($scope, $filter) { //Do not forget to inject $filter
$scope.currentPage = 0;
$scope.pageSize = 10;
$scope.data = [];
$scope.numberOfPages=function(){
var myFilteredData = $filter('filter')($scope.data,$scope.search_notes); //Filter the data
return Math.ceil(myFilteredData.length/$scope.pageSize);
}
for (var i=0; i<45; i++) {
$scope.data.push("Item "+i);
}
}
In addition, I would modify the ng-disable next button to
button "ng-disabled="(currentPage + 1) == numberOfPages()"
And I would add to search_notes onchange currentPage=1.
Here you have the fiddle
http://jsfiddle.net/rLots5zd/
In case, you want to hide the next and previous button when the result can be displayed in one page, please see the fiddle here: http://jsfiddle.net/rLots5zd/3/

Resources