Angular JS with jquery masonry - angularjs

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.

Related

Detecting an image is fully loaded from a directive, where the directive is not applied to the image element

there are many examples in SO on how we can use an angular directive to know when an image is loaded. The examples describe a directive that is directly applied to the img element like so:
<img ng-src="myimage.jpg" my-great-directive />
And then in the directive "my-great-directive"
we can do an:
element.bind("load" , function(e){ }
And i works great.
However, what if the construct is like this:
<div my-great-directive>
<img ng-src="myimage.jpg" />
</div>
Within my-great-directive, how do I bind to the inside image loaded event?
This is not really a theoretical problem for me. I am using a 3rd party slider called angular-carousel-slider that wraps around like so:
<ul rn-carousel rn-carousel-buffered
rn-carousel-index="mycarousel.index"
rn-carousel-auto-slide="0.3" rn-carousel-pause-on-hover >
<li ng-repeat="slide in slides">
<img ng-src="{{eventBasePath}}{{slide.img}}?rand={{rand}}"/>
</li>
</ul>
I'm trying to modify its code so that it does not slide to the next image unless the current image is fully loaded (to avoid the situation of a fast slider half loading images and moving to the next). I'm stuck on how I can trap this image loaded event inside the directive. Doing element.bind("load") does not work as the directive is not applied to the image element.
Thank you!
Check this working demo: JSFiddle
Use anguler.element to find the img element and bind the event.
In your directive, it should be element.find('img').
angular.module('Joy', [])
.directive('hello', [function () {
return {
restrict: 'A',
link: function (scope, ele) {
var img = ele.find('img');
console.log(img);
img.bind('load', function () {
console.log('img is loaded');
});
}
};
}]);
HTML:
<div ng-app="Joy">
<div hello>
<img ng-src="https://www.google.com.hk/images/srpr/logo11w.png">
</div>
</div>
Update 1
If use ng-repeat, add a $timeout to wait for ng-repeat finishes first. Check working demo: JSFiddle.
Note: this demo is loading a very large image. After the image is loaded, the text img is loaded will be shown.
Update 2
If the event binding is not working, try native image.onload binding (or oncomplete to find images cached). Working demo: JSFiddle.

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);
};
}

Kendo UI and angular - no widget in $scope

I'm using Kendo UI version 2014.2.716 with AngularJS version 1.2.27, and I made a grid using a directive
<div ng-controller="MyController as ctrl">
<div id="myGrid" kendo-grid k-options="{some options}"></div>
<button ng-click="ctrl.doSomething()"></div>
</div>
I read that if you give a name to the grid (like this: kendo-grid="myGridOnScope"), you can access the widget in the controller scope in this way:
myModule.controller('MyController', function($scope) {
this.doSomething = function() {
console.log($scope.myGridOnScope);
}
}
The console.log should log a widget object, but in my case it's undefined. What am I doing wrong? Thanks for the help
I have found out the problem myself, so I'm going to post an answer if someone has the same problem. If you use the controllerAs syntax in AngularJS, you can't just write the name of the widget - you have to prefix it with your controller alias.
Take a look at this example:
<div ng-controller="MyController as ctrl">
<div kendo-grid="myGridName"></div>
</div>
This will not give you the grid object on the $scope - for that you need to add the ctrl prefix:
<div ng-controller="MyController as ctrl">
<div kendo-grid="ctrl.myGridName"></div>
</div>
Now you have access to the widget in your controller like this:
angular.module('MyModule',['kendo.directives'])
.controller('MyController', function($scope){
// this gives you the widget object
console.log(this.myGridName);
// however, this doesn't work
console.log($scope.myGridName);
});
I hope I helped someone with this post.
Cheers,
Try waiting for the event that Kendo emits.
Html
<div kendo-grid="grid" options="gridOptions"></div>
Javascript
$scope.$on("kendoWidgetCreated", function(event, widget){
if (widget === $scope.grid) {
console.log($scope.grid);
}
});
Edit: See this Plunker
It is because angular is too fast and the kendo element doesn't exist when you try to set the options.
I solved this with a watch.
This is my html code:
<div kendo-grid="ListDesign"></div>
And this is my angular code
$scope.$watch('ListDesign', function () {
if ($scope.ListDesign != undefined) {
var gridOptions = {
columns: columns,
sortable: {
mode: 'multiple',
allowUnsort: true
}
};
$scope.ListDesign.setOptions(gridOptions);
$scope.ListDesign.setDataSource(dataSource);
}
});
Does this answer your question?

ng-repeat with ng-include not working

I am trying to use an ng-repeat that includes an ng-include. The problem is that the first element in the ng-repeat is just the ng-include template with none of the data from the ng-repeat filled in. Is there a way I can somehow bind the template from the ng-include so it works on the first ng-repeat?
<div ng-repeat="item in items">
<div ng-include src="'views/template.html'"></div>
</div>
For example, if my ng-repeat contains 10 items, then the first item that is rendered will just be the empty template. Items 2-10 WILL be rendered as they should be. What am I doing wrong?
First make sure that the data that is contained in the first index of items actually has the data that you want.
One possible solution to your problem would be to simply not show the first index of the ng-repeat:
<div ng-repeat="item in items" ng-show="!$first">
<div ng-include src="'views/template.html'"></div>
</div>
This may not actually tackle the root of your problem, but it may still get your application working a bit more like what you expect.
Another possible solution:
<div ng-repeat="item in items" ng-include="'views/template.html'"></div>
see example here:
http://plnkr.co/edit/Yvd73HiFS8dXvpvpEeFu?p=preview
One more possible fix just for good measure:
Use a component:
html:
<div ng-repeat="item in items">
<my-include></my-include>
</div>
js:
angular.module("app").directive("myInclude", function() {
return {
restrict: "E",
templateUrl: "/views/template.html"
}
})
I ran into the same problem, and finally figured out that the first element has not been fetched and compiled in time for the first ng-repeat iteration. Using $templateCache will fix the problem.
You can cache your template in a script tag:
<script type="text/ng-template" id="templateId.html">
<p>This is the content of the template</p>
</script>
Or in your app's run function:
angular.module("app").run(function($http, $templateCache) {
$http.get("/views/template.html", { cache: $templateCache });
});
You can also use $templateCache inside your directive, although it's a bit harder to setup. If your templates are dynamic, I would recommend creating a template cache service. This SO question has some good examples of template caching inside a directive and a service:
Using $http and $templateCache from within a directive doesn't return results
Using a directive worked for me: https://stackoverflow.com/a/24673257/188926
In your case:
1) define a directive:
angular.module('myApp')
.directive('mytemplate', function() {
return {
templateUrl: 'views/template.html'
};
});
2) use your new directive:
<mytemplate />
... or if you're concerned about HTML validation:
<div mytemplate></div>

Using AngularJS select ng-options with Semantic UI's dropdown

So Semantic UI appears to the latest 'hot' UI framework which I'm impressed with; however, their dropdown isn't an implementation of the HTML 'select' and 'option' tags but instead custom. For my project, I'm using AngularJS which is phenomenal JavaScript MVW framework.
How can I integrate AngularJS select ng-option with Semantic UI's dropdown? I'm not much of a JS pro. Here's the JSfidde: http://jsfiddle.net/fMUy3/
<!doctype html>
<html ng-app="App">
<body ng-controller="MainCtrl">
<h3>Option 1 (standard)</h3>
<select ng-model="selectedItem" ng-options="c as (c.id + ' - ' + c.name) for c in containers">
<option value="">-- Pick A Container --</option>
</select>
<br>ID: {{selectedItem.id}}
<br>Name: {{selectedItem.name}}
<h3> Semantic UI Dropdown</h3>
<div class="ui selection dropdown ">
<input name="id" type="hidden" value="0">
<div class="text">-- Pick A Container --</div> <i class="dropdown icon"></i>
<div class="menu transition hidden">
<div class="item active">-- Pick A Container --</div>
<div data-value="{{container.id}}" class="item" ng-repeat="container in containers">{{container.name}}</div>
</div>
</body>
</html>
JavaScript:
var app = angular.module('App', []);
app.controller('MainCtrl', function($scope) {
$scope.containers = [
{id: 1, name: 'Box1'},
{id: 2, name: 'Box2'},
{id: 3, name: 'Box3'}];
//$scope.selectedItem = $scope.containers[0];
});
$('.ui.dropdown').dropdown();
Much appreciated!
There were a few things wrong with your fiddle. The first was that the semantic-ui JavaScript was being loaded before jQuery. It depends on jQuery so jQuery must be loaded first. (Also, loading jQuery before AngularJS is recommended.)
The second thing is that the semantic dropdown function was being called before AngularJS had a chance to unroll the repeater that creates the options. This means the options were not there when semantic did its dropdown thing. As a simple solution I made a timeout that would fire on the next processing loop; after AngularJS has done its thing. You can see that semantic dropdown now works
This is more of a simple proof of concept to demo the timing of things and should not be used.
http://jsfiddle.net/fMUy3/1/
$timeout(function(){
$('.ui.dropdown').dropdown();
},0)
How this should be handled is with a directive that will take care of the timings so that you do not need to use the timeout and would not need to specify each dropdown in the controller. Here is the example using a directive (which would handle all cases)
http://jsfiddle.net/fMUy3/7/
app.directive('dropdown', function ($timeout) {
return {
restrict: "C",
link: function (scope, elm, attr) {
$timeout(function () {
$(elm).dropdown().dropdown('setting', {
onChange: function (value) {
scope.$parent[attr.ngModel] = value;
scope.$parent.$apply();
}
});
}, 0);
}
};
});
Your first problem is you need to include semantic.js after jquery.
Second, you can't use ng-options on a div repeater but you can simulate it by using a ng-click
HTML
<div data-value="{{container.id}}" class="item" ng-repeat="container in containers" ng-click="select(container)">
{{container.name}}
</div>
JS
$scope.select = function(container) {
$scope.selectedItem = container;
};
see this updated fiddle

Resources