call a function after completely loaded into html with ng-repeate - json

how can I call a function after completely loaded my json data from the server into a ng-repeate?
Ex: I have json URL it have some products data which is in my car, once I clicked on view cart the cart items should be showed in the popup box. and if add another product it should me added in the popup box.
Please help me guys

HTML
<div data-ng-controller="MainController">
<ul>
<li ng-repeat="asset in assets" my-directive>{{asset}}</li>
</ul>
</div>
JS
var app = angular.module('myApp', []);
app.controller('MainController',function($scope) {
$scope.assets = [1,2,3,4,5,6,7,8,9,10];
});
app.value('myFunc',function(){
alert('Hello');
});
app.directive('myDirective', function( myFunc) {
return {
restrict: 'A',
link: function(scope, elem) {
if (scope.$last){
myFunc();
}
}
};
});
It should work also with a asyn service (to get data)

Related

Unable to invoke a custom directive inside another custom directive in AngularJs

I want to invoke a custom directive inside another custom directive's template.
Please find below code snippets -
Scenario 1 (Not working)
angular.module('myApp')
.directive('customOnChange', function () {
return {
restrict: 'A',
link: function (scope, element, attrs) {
var onChangeFunc = scope.$eval(attrs.customOnChange);
element.bind('change', function (event) {
var files = event.target.files;
onChangeFunc(files);
});
element.bind('click', function () {
element.val('');
});
}
};
})
.directive('writePost', function () {
return {
restrict: 'E',
link: function (scope) {
scope.changeUserProfileImage = function (files) {
console.log(files); // I should receive uploaded files here.
};
},
templateUrl: function () {
return 'writePost.html';
}
};
});
index.html
<write-post></write-post>
writePost.html
<input type="file" ng-model="file" name="file"
id="photo-upload1" custom-on-change="changeUserProfileImage"
value="Change Image"
title="Change Image"/>
The error I am receiving when I upload a file -
Uncaught TypeError: onChangeFunc is not a function
Scenario 2 (Working)
Although independently I am able to call customOnChange directive from index.html. Working code snippet -
index.html
<input type="file" ng-model="file" name="file"
id="photo-upload1" custom-on-change="changeUserProfileImage"
value="Change Image"
title="Change Image"/>
myCtrl.js
angular.module('myApp')
.controller('myCtrl', ['$scope', function ($scope) {
$scope.changeUserProfileImage = function (files) {
console.log(files); // I am receiving uploaded files here.
};
}]);
Can someone help me identifying, where I am going wrong in first scenario ?
link in directive definition defaults to postLink - it executes after template with its directives is parsed. (read more here https://docs.angularjs.org/api/ng/service/$compile#pre-linking-function)
As a solution you can move $eval inside callback:
element.bind('change', function (event) {
var onChangeFunc = scope.$eval(attrs.customOnChange);
var files = event.target.files;
onChangeFunc(files);
});
Correct way:
If you want run function - let it be function in html:
custom-on-change="changeUserProfileImage(files)"
Now run it as function:
element.bind('change', function (event) {
var files = event.target.files;
scope.$eval(attrs.customOnChange, {files: event.target.files});
});

Sorting with isotope from external json rendered with handlebars

Can't seem to get Isotope sort to work :(
On the client side of a webpage I'm displaying data which comes from an external json with a template using handlebars.js.
I want the users to be able to sort, filter and search the data that is displayed. I've seen that with Isotope can this be achieve successfully. I did manage to get filtering to work.
However I'm stuck with sorting in targeting the class of the object with the getSortData option which value comes from the json.
Example of the JSON structure with the price:
Here is the code trying to sort by price, first my menu:
<ul id="sort">
<li>original order</li>
<li>number</li>
</ul>
Then my handlebars template, where I want to reach the p.class = number:
<div id="mcContainer"></div>
<script id="mcTemplate" type="text/x-handlebars-template">
{{#each this}} {{#annoncer}}
<article class="mc_item {{category}} {{year}}">
<a data-single href="{{id}}">
<h3>{{brand}} {{model}}</h3>
<img src={{images.0.small}} />
<h4 class="mc_aar">ÅR: {{year}}, {{km}} km</h4>
<p>{{category}}</p>
<p class="mc_pris number">{{price}},-</p>
<hr>
</a>
</article>
{{/annoncer}} {{/each}}
</script>
And my javascript file:
(function ($) {
"use strict";
// javascript code here. i.e.: $(document).ready( function(){} );
$(document).ready(function ($) {
var $container = $('#mcContainer');
$.ajax({
url: "http://diegovega.dk/kea/2semester/json-eks/json-eks.json",
method: "GET",
dataType: 'json',
success: function (response) {
var template = $('#mcTemplate').html();
var renderer = Handlebars.compile(template);
var result = response;
$('#mcContainer').html(renderer(result));
runIsotope();
}
});
function runIsotope() {
var $items = $('.mc_item');
$items.isotope({})
$items.isotope('reloadItems')
.isotope({
itemSelector: '.mc_item',
layoutMode: 'fitRows',
fitRows: {
gutter: 20
},
getSortData: {
number: '.number parseInt'
},
});
// Sort based on price
$('#sort').on('click', function () {
if ($(this).hasClass('checked')) {
$(this).removeClass('checked');
.isotope({
sortBy: 'original-order'
});
} else {
$('#sort').removeClass('checked');
var sortValue = $(this).attr('data-sort-value');
console.log($(this).attr('data-sort-value'));
.isotope({
sortBy: sortValue
});
$(this).addClass('checked');
}
});
} //RUN ISOTOPE
}); // END DOCUMENT READY
})(jQuery); // END use strict
Any help is greatly appreciated :)
Initialize Isotope on the container, not the items
Use data-sort attribute on the links click

Angular service not storing data between two controllers

I am trying to use a service to set title in controller1 and then access title in controller2.
sharedProperties.setTitle(title) works in controller1, but when I try to get the title in controller2, it gets "title" (the initial value) instead of the new value.
I've also tried storing title in an object but it didn't work.
app.service('sharedProperties', function () {
var title = "title"
return {
getTitle: function () {
return title;
},
setTitle: function (val) {
title = val;
}
}
});
app.controller('controller1', ['$scope', 'sharedProperties', function ($scope, sharedProperties) {
$('body').on("click", "button[name=btnListItem]", function () {
// gets the title
var title = $(this).text();
// sets the title for storage in a service
sharedProperties.setTitle(title);
});
}]);
app.controller('controller2', ['$scope', 'sharedProperties', function ($scope, sharedProperties) {
$scope.sharedTitle = function() {
return sharedProperties.getTitle();
};
}]);
And in my view, I have {{ sharedTitle() }} which should, as I understand it, update the title text with the new title.
Also, in case this is relevant: the two controllers are linked to two different html pages.
What am I doing wrong?
EDIT
Updated button listener:
$('body').on("click", "button[name=btnListItem]", function () {
// gets the text of the button (title)
var title = $(this).text();
sharedTitle(title);
alert(sharedProperties.getTitle());
document.location.href = '/nextscreen.html';
});
$scope.sharedTitle = function (title) {
sharedProperties.setTitle(title);
};
It seems to be correct in your sample code. I setup jsfiddle and it seems work correctly. Finding out a difference between my jsfiddle and your actual code would help you to find the problem you should solve.
Javascript:
angular.module('testapp', [])
.service('sharedProperties', function(){
var title = 'title';
return {
getTitle: function(){
return title;
},
setTitle: function(val){
title = val;
}
};
})
.controller('controller1', function($scope, sharedProperties){
$scope.change_title = function(newvalue){
sharedProperties.setTitle(newvalue);
};
})
.controller('controller2', function($scope, sharedProperties){
$scope.sharedTitle = function(){
return sharedProperties.getTitle();
};
})
Html:
<div ng-app="testapp">
<div ng-controller="controller1">
<input ng-model="newvalue">
<button ng-click="change_title(newvalue)">Change Title</button>
</div>
<div ng-controller="controller2">
<span>{{sharedTitle()}}</span>
</div>
</div>
My jsfiddle is here.
You have to print console.log(sharedProperties.getTitle()); Dont need return from controller.
So your code of controller2 is $scope.sharedTitle = sharedProperties.getTitle();
You need to use the $apply so that angular can process changes made outside of the angular context (in this case changes made by jQuery).
$('body').on("click", "button[name=btnListItem]", function () {
// gets the title
var title = $(this).text();
// sets the title for storage in a service
$scope.$apply(function() {
sharedProperties.setTitle(title);
});
});
See plunker
That said, this is BAD PRACTICE because you're going against what angular is meant for. Check “Thinking in AngularJS” if I have a jQuery background?. There are cases when you need to use $apply like when integrating third party plugins but this is not one of those cases.

TinyMCE and AngularJS - not loading after NgSwitch

I hope I am clear enough with this request for assistance, as it is hard to explain and I can't post all the code here. I have downloaded code to enable TinyMCE to be used in a NgRepeat with AngularJS:
angular.module('ui.tinymce', [])
.value('uiTinymceConfig', {})
.directive('uiTinymce', ['uiTinymceConfig', function (uiTinymceConfig) {
uiTinymceConfig = uiTinymceConfig || {};
var generatedIds = 0;
return {
require: 'ngModel',
link: function (scope, elm, attrs, ngModel) {
var expression, options, tinyInstance;
// generate an ID if not present
if (!attrs.id) {
attrs.$set('id', 'uiTinymce' + generatedIds++);
}
options = {
// Update model when calling setContent (such as from the source editor popup)
setup: function (ed) {
ed.on('init', function (args) {
ngModel.$render();
});
// Update model on button click
ed.on('ExecCommand', function (e) {
ed.save();
ngModel.$setViewValue(elm.val());
if (!scope.$$phase) {
scope.$apply();
}
});
// Update model on keypress
ed.on('KeyUp', function (e) {
ed.save();
ngModel.$setViewValue(elm.val());
if (!scope.$$phase) {
scope.$apply();
}
});
},
mode: 'exact',
elements: attrs.id
};
if (attrs.uiTinymce) {
expression = scope.$eval(attrs.uiTinymce);
} else {
expression = {};
}
angular.extend(options, uiTinymceConfig, expression);
setTimeout(function () {
tinymce.init(options);
});
ngModel.$render = function () {
if (!tinyInstance) {
tinyInstance = tinymce.get(attrs.id);
}
if (tinyInstance) {
tinyInstance.setContent(ngModel.$viewValue || '');
}
};
}
};
}]);
var gwApp = angular.module('gwApp', ['ui.tinymce']);
I don't really understand this code, but it works fine initially. My page starts with a list of Posts. I click on 'Show Reply' for the first post, and using NgSwitch the multiple replies become visible (nested NgRepeat). I submit a new reply message (the reply text is entered using tinymce) using a RESTful API service and a http call (too much code to post here). Then after clicking the submit button for the new reply message, the NgSwitch kicks in again unexpectedly to make the replies no longer visible. When I expand the replies again, the tinymce is just a regular textarea again, and the proper editor is gone.
I know this is not very clear, but I'm hoping someone can make sense of what I've written and can help me solve this problem..
I was having the same problem using ng-switch and ng-show so i added:
scope.$watch('onHidden()',function(){ tinymce.editors = [] });
after the setTimeout function.
Also replace the
ed.on('init',function(args){ ngModel.$render(); });
with
ed.on('init',function(args){ ed.setContent(ngModel.$viewValue); });
and remove the $render function.
This is the link to the working code in JsFiddle

Angular - append html through different frames with one module per frame

My code have the main windonw and one iframe and each one with your module. A button in main window fires click event that should append html into iframe, the new html when appended into that should apply interceptors and directives properly, but it doesn't work!
Angular javascript:
angular.module('module1',[]).controller('Controller1', function ($scope) {
$scope.get = function(){
$http.jsonp("some_url_here").success(function(html){
$scope.content = html;
});
}
}).directive('click', function($compile) {
return {
link: function link(scope, element, attrs) {
element.bind('click',function(){
var unbind = scope.$watch(scope.content, function() {
var div=document.getElementById("frame").contentWindow.angular.element("divId");
div.append($compile(scope.content)(div.scope()));
unbind();
});
});
}
}
});
angular.module('module2',[]).directive('a', function() {
return {
restrict:'E',
link: function(scope, element, attrs) {
console.log('ping!');
console.log(attrs.href);
}
};
});
Html code:
<html ng-app="modile1">
<div ng-controller="Controller1">
<button type="button", ng-click="get('any_value')", click:""/> Load frame
</div>
<iframe id="frame" src="/please/ignore/this">
<!-- considere the html as appended from iframe-src and contains ng-app="module2" -->
<html ng-app="module2">
<div id="divId">
<!-- code should be inject here -->
</div>
</html>
</iframe>
</html>
Please, considere that angularjs, jquery if applicable, modules-declaration as well as headers are loaded properly.
I'd like to load the html content from main-frame/window into iframe and run interceptors and directives properly. Is it possible? If yes, how can I do it?
Thanks for advancing!
I've tried this code and it seems work fine! I found it here: http://www.snip2code.com/Snippet/50430/Angular-Bootstrap
var $rootElement = angular.element(document.getElementById("frame").contentWindow.document);
var modules = [
'ng',
'module2',
function($provide) {
$provide.value('$rootElement', $rootElement)
}
];
var $injector = angular.injector(modules);
var $compile = $injector.get('$compile');
$rootElement.find("div#divId").append(scope.content);
var compositeLinkFn = $compile($rootElement);
var $rootScope = $injector.get('$rootScope');
compositeLinkFn($rootScope);
$rootScope.$apply();