View updating after $http.get but not ng-repeat - angularjs

I am using $http.get to return a JSON array. If I simply echo the array it prints in the view fine. However, my ng-repeat container does not update.
To further confuse, I have a filter on the data which, when I filter for filename e.g. beginning with the number 1, suddenly they all appear (that match the filter anyway as they should).
Here's what I'm trying:
capApp.controller('myUploadedPhotos', function ($scope, $http) {
$http.get("http://myurl.com/ajax/myUploadedPhotos.php")
.success(function(response) {
$scope.photos = response;
});
});
<div ng-controller="myUploadedPhotos" class="container">
<h1>Hey {{photos}}</h1> <!-- this prints the array to the screen perfectly -->
<div class="photo" ng-repeat="x in photos | filter: { filename: nameFilter } | orderBy: order">
// this doesn't show any images until I filter
<img ng-src="/uploads/{{ x.filename }}" />
</div>
No errors anywhere by the way.
Any ideas how I could fix this?
UPDATE
It's clearly something to do with the filter, when I remove it, all works ok and images show.
This is the filter field:
<div>Filename: <input type="text" ng-model="nameFilter" /></div>
Should I be somehow setting this to "" on init?

Related

Angularjs get data filtered in ng-repeat from controller

I have tried everything but I can't get it.
What i need is to access data filtered in ng-repeat from controller.
Data in ng-repeat is taken from a $http call.
$http.get('http://localhost:/test/test.php').success(function(data) {
$scope.registros = data;
});
and this is the view
<div ng-repeat="registro in (filteredregistros = (registros| filter:userSearch | filter:datefilter | filter:greaterThan('ID', greatersearch) | orderBy:'-ID'))">
{{registro.ID}}{{registro.date}}
<div class="rowboxdata ng-animate">
<div class=""><div class="name-business">{{registro.Name}}</div></div>
<div class=""><div class="name-business">{{registro.Phone}}</div></div>
<div class=""><div class="name-business">{{registro.Email}}</div></div>
<div class=""><div class="name-business">{{registro.Name}}</div></div>
<div class=""><div class="name-business">{{registro.City}}</div></div>
<div class=""><div class="name-business">{{registro.Service}}</div></div>
</div>
</div>
I have tried access data filtered from my controller with $scope.filteredregistros as i look in other post, but it didn't work to me.
What I'm trying to do, is to get data filtered and then, send it through ajax to php.
Would be nice some help thanks.
EDITED
Finally, I have found what I needed with this example;
In the View:
<input type="button" ng-click="results(filteredregistros)" />
In the Controller:
$scope.results = function (filteredregistros) {
console.log(filteredregistros);
// your ajax code
};
And if you want to get it only in the view, then do it as Per Hornshøj-Schierbeck says:
filteredregistros: {{filteredregistros | json}}
Thanks for the help Per Hornshøj-Schierbeck
Try adding
filteredregistros: {{filteredregistros | json}}
in your HTML somewhere. It should be clear if it contains data or not. Piping it through json will display the data in json format, which is nice for debugging the value inside.
The reason why you might not see if, when you do console.log is, that depending on when you console.log it, your http request might or might not have run and the data might not be filtered yet.

Make one filter override the other with a name filter angularJS

I have an array of data which I display using ng-repeat in AngularJS. The displayed data is filtered and then paginated based on user inputs, with the filter referring to a function in the controller.
Now what I want to do is to over-ride the current filter criteria if a user inputs text into a search field and only filter based on the inputted text. I.e. if a user inputs text then the other filters no longer apply and instead use the text filter. I feel like the way I have set it up it would be something around creating an if function in the controller's filter function and then re-creating the angular filter by text javascript. However, I am not sure how to do that and even if it is the right way.
Below is a snippet of the code which hopefully gives a good outline of the current state and what I am trying to achieve.
TEXT SEARCH HTML
<input
ng-model="searchData.query"
type="text"
name="productname"
id="productname"
class="form-control productname-answer">
FILTER HTML
<div ng-repeat="product in (productsFilterd = (productData | filter: {productfilter:true} | orderBy:'relevance':true)).slice(((productData.currentPage-1)*productData.itemsPerPage), ((productData.currentPage)*productData.itemsPerPage))">
...
</div>
CONTROLLER
$scope.getProductfilter = function() {
for (i = 0; i < $scope.productprofiles.length; i++) {
if ($scope.productprofiles[i].reqlanguagecompara === 1 && $scope.productprofiles[i].reqservicecompara === 1) {
$scope.productprofiles[i].productfilter = true;
}
else {
$scope.productprofiles[i].productfilter = false;
};
};
};
Please check a simplified working demo: http://jsfiddle.net/c85gq14k/6/.
Try to wrap the logic into two filters function, one for default and one for customized:
angular.module('Joy', [])
.controller('FilterCtrl', ['$scope', function ($scope) {
$scope.defaultFilter = function (n) {
return n > 5;
};
$scope.inputFilter = function (n) {
if ($scope.number) {
return n > $scope.number;
}
return $scope.defaultFilter(n);
};
}]);
The HTML is like:
<div ng-app="Joy">
<div ng-controller="FilterCtrl" id="play-ground">
<input type="text" ng-model="number">
<div>
<ul>
<li ng-repeat="i in ([1,2,3,5,8,13,21,34] | filter:inputFilter )" ng-bind="i"></li>
</ul>
</div>
</div>
</div>
Whenever you enter a number, the default filter n>5 is not applied.

Live search in AngularJS: updating the results

I want a live search: the results are queried from web api and updated as the user types.
The problem is that the list flickers and the "No results" text appears for a fraction of second, even if the list of results stays the same. I guess I need to remove and add items with special code to avoid this, calculating differences between arrays, etc.
Is there a simpler way to avoid this flicker at least, and probably to have possibility to animate the changes?
It looks like this now:
The html part is:
<div class="list-group">
<a ng-repeat="test in tests track by test.id | orderBy: '-id'" ng-href="#/test/{{test.id}}" class="list-group-item">
<h4 class="list-group-item-heading">{{test.name}}</h4>
{{test.description}}
</a>
</div>
<div ng-show="!tests.length" class="panel panel-danger">
<div class="panel-body">
No tests found.
</div>
<div class="panel-footer">Try a different search or clear the text to view new tests.</div>
</div>
And the controller:
testerControllers.controller('TestSearchListCtrl', ['$scope', 'TestSearch',
function($scope, TestSearch) {
$scope.tests = TestSearch.query();
$scope.$watch('search', function() {
$scope.tests = TestSearch.query({'q':$scope.search});
});
}]);
You should use ng-animate module to get the classes you need for smooth animation. For each ng-repeat item that's moved, added, or removed - angular will add specific classes. Then you can style those classes via CSS or JS so they don’t flicker.
An alternative way of doing what you require is to use the angular-ui bootstrap Typeahead component (check at the bottom of the post). It has a type-ahead-wait property in milliseconds and also a template url for customising it.
<div ng-app>
<div ng-controller="MyController">
<input type="search" ng-model="search" placeholder="Search...">
<button ng-click="fun()">search</button>
<ul>
<li ng-repeat="name in names">{{ name }}</li>
</ul>
<p>Tips: Try searching for <code>ann</code> or <code>lol</code>
</p>
</div>
</div>
function MyController($scope, $filter) {
$scope.names = [
'Lolita Dipietro',
'Annice Guernsey',
'Gerri Rall',
'Ginette Pinales',
'Lon Rondon',
'Jennine Marcos',
'Roxann Hooser',
'Brendon Loth',
'Ilda Bogdan',
'Jani Fan',
'Grace Soller',
'Everette Costantino',
'Andy Hume',
'Omar Davie',
'Jerrica Hillery',
'Charline Cogar',
'Melda Diorio',
'Rita Abbott',
'Setsuko Minger',
'Aretha Paige'];
$scope.fun = function () {
console.log($scope.search);
$scope.names = $filter('filter')($scope.names, $scope.search);
};
}

Ng-repeat wont work

JS:
function ctrlr($scope, $http) {
$http.post(urlhere).success(function(data) {
$scope.Items = data;
});
}
HTML:
<body ng-app="">
<div ng-controller="ctrlr">
<div ng-repeat="item in Items">
{{ item.Name }}
</div>
</div>
</body>
Data returned from post request is a list of a class object (that contains Name property)
Checked, data is not empty.
It returns an xml formatted response.
Why won't my ng-repeat work? Tried using jquery ajax, which returned json but still no go
If you're running ng-repeat on a js object instead of array you should do something like this
<div ng-repeat="(key, val) in Items">
<span>{{key}}</span>
<span>{{val}}</span>
Well it may sound silly but the problem was that $scope.Items is being initialized in the success, an async method so it was undefined when it arrived to ng-repeat.
I solved it by switching to jquery ajax and adding async: false

Angular JS with jquery masonry

I need to use angular and masonry and also implement sorting and filtering.
The fiddle here does use the masonry with Angular and has filtering and sorting working, however the layout does not seem like masonry. I do not think the masonry layout is applied at all.
http://jsfiddle.net/rdikshit/6swek/3/
<div ng-app="test">
<div ng-controller="MainCtrl">
<input type="text" ng-model="nameFilter" />
Order by id
Order by name
Order by age
<div class="items" masonry >
<div ng-repeat="item in items | filter: { name: nameFilter } | orderBy: order:reverse" class={{item.style}}>
<span>{{item.name}}</span>
<span>id: {{item.id}}</span>
<br /> <span>Age: {{item.age}}</span>
<br /> <span>Style: {{item.style}}</span>
</div>
</div>
</div>
</div>
Here is another fiddle with Passy's directive:
http://jsfiddle.net/rdikshit/6swek/5/
STill does nt work. Even the sorting and filtering are not working now.
I modified your JSFiddle and got it to work. Since columnWidth is not specified, the width of the first element is used. That's why there is gap between the elements sometimes
Few points to look out for:
Don't save the Masonry instance, since you are using the JQuery version. To access Masonry methods, simply get the container element then do container.masonry( 'methodName', arguments );
The watches in the controller are not ideal, in a real app you probably want to put them into a directive
The technique where you watch the number of children in the Masonry container doesn't work when you have ngAnimate as one of your dependency. It cause the DOM tree to be updated after $digest(), which make $watch miss
I am working on a simular project, but i am using Isotope with a mansory style.
here is the way i am using it:
Directive:
app.directive('isotope', function ($timeout) {
return {
scope: {
items: '=isotope'
},
templateUrl: 'social-item.html',
link: function (scope, element, attrs) {
var options = {
animationEngine : 'jquery',
itemSelector: '.social-item',
layoutMode: 'masonry',
masonry : {
"gutter": 10,
"isFitWidth": true
}
};
element.isotope(options);
scope.$watch('items', function() {
$timeout(function() {
element.isotope( 'reloadItems' ).isotope();
});
},true);
}
};
});
Directive template (social-item.html):
<div class="social-item" ng-repeat="item in items track by $index">
<!--
Do something with item, in your case something like this:
<span>{{item.name}}</span>
<span>id: {{item.id}}</span>
-->
</div>
HTML Markup:
<div class="social-wall-container" isotope="socials.posts">
<!-- repeat posts from directive -->
</div>
For more information about isotope checkout This link
If you decide to use isotope, make sure to include the necesary files located in the JS folder on the github page.

Resources