Angular ng-init function loaded after directive - javascript

THE SITUATION:
Hello guys! I have an app where is possible to upload file. In the file page, if the file is a pdf file, the app display a little preview of the file.
I am using this very useful directive: angular-pdf-viewer
If i hardcode the path into a scope variable initialized in the controller everything works smoothly.
But of course i have to get some file info that i need for the path.
To do that i have a function that I call with ng-init.
The path is taken properly but the problem is that come too late..
In the console first i see the error message coming from the directive (because it does not find the file) and THEN, right after the error message, i see a console test message coming from the function.
That means that the path is loaded too late and not found by the directive
THE ERROR MESSAGE:
Error: Invalid parameter object: need either .data, .range or .url
THE DIRECTIVE:
app.directive('myPdfViewerToolbar', [
'pdfDelegate',
function(pdfDelegate) {
return {
restrict: 'E',
template:
'<div class="clearfix mb2 white bg-blue">' +
'<div class="left">' +
'<a href=""' +
'ng-click="prev()"' +
'class="button py2 m0 button-nav-dark">Back' +
'</a>' +
'<a href=""' +
'ng-click="next()"' +
'class="button py2 m0 button-nav-dark">Next' +
'</a>' +
'<span class="px1">Page</span> ' +
'<input type="text" class="field-dark" ' +
'min=1 ng-model="currentPage" ng-change="goToPage()" ' +
'style="width: 10%"> ' +
' / {{pageCount}}' +
'</div>' +
'</div>',
scope:
{
pageCount: '='
},
link: function(scope, element, attrs) {
var id = attrs.delegateHandle;
scope.currentPage = 1;
scope.prev = function() {
pdfDelegate
.$getByHandle(id)
.prev();
updateCurrentPage();
};
scope.next = function() {
pdfDelegate
.$getByHandle(id)
.next();
updateCurrentPage();
};
scope.goToPage = function() {
pdfDelegate
.$getByHandle(id)
.goToPage(scope.currentPage);
};
var updateCurrentPage = function() {
scope.currentPage = pdfDelegate
.$getByHandle(id)
.getCurrentPage();
};
}
};
}]);
THE VIEW:
<h2>File preview</h2>
<my-pdf-viewer-toolbar
delegate-handle="my-pdf-container">
</my-pdf-viewer-toolbar>
<pdf-viewer
delegate-handle="my-pdf-container"
url="file_url"
scale="1"
show-toolbar="false">
</pdf-viewer>
THE FUNCTION:
$scope.get_file_path = function()
{
var deferred = $q.defer();
$http({
method: 'POST',
url: base_url + 'api/get_file_detail/' + $stateParams.file_id
})
.success( function( data, status, headers, config )
{
deferred.resolve( data );
$scope.file_url = base_url + 'data/localhost/drawer/' + data.data_id + '/' + data.filename;
console.log($scope.file_url);
})
.error( function( data, status, headers, config )
{
deferred.reject( data );
});
}
THE QUESTION:
There another way to load the function before?
Or, how can i pass the file path to the directive?
Thank you very much!

Ok there is an easy solution: Wrap the directive inside an ng-if, in this way the directive is loaded only after the path has been initialized.
<div ng-if="file_url">
<pdf-viewer
delegate-handle="my-pdf-container"
url="file_url"
scale="1"
show-toolbar="false">
</div>

Related

populating a unite gallery using ajax

Hi i am currently trying to populate a unite gallery using ajax however the gallery is just hanging with a loading icon and not displaying any of the images any help with be appreciated
Ajax
$('document').ready(function () {
var folder = "http://localhost/client%20side%20web%20coursework/files/";
jQuery("#gallery").unitegallery();
$.ajax({
url: folder,
asynch: false,
cache: false,
success: function (data) {
$(data).find("a").attr("href", function (i, val) {
if (val.match(/\.(jpe?g|png|gif)$/)) {
$("#gallery").append("<img alt='uploaded file' src='" + folder + val + "'data-image='" + folder + val + "'data-description='uploaded file by user'>'");
}
});
}
});
});
div we are trying to populate
<div id="gallery" style="display:none;">
</div>
the documentation for unite gallery can be found here for anyone who is not familiar with it http://unitegallery.net/index.php?page=documentation#installing_the_gallery
Any help will be appreciated
$('document').ready(function(){
var folder = "http://localhost/client%20side%20web%20coursework/files/";
$.ajax({
url : folder,
asynch : false,
cache : false,
success: function (data) {
var $gallery = $("#gallery");
var imgsToAppend = '';
$(data).find("a").each(function(i, el) {
var val = $(el).attr('href');
if (val.match(/\.(jpe?g|png|gif)$/)) {
imgsToAppend+="<img alt='uploaded file' src='" + folder + val + "' data-image='" + folder + val + "' data-description='uploaded file by user'>";
}
});
if(imgsToAppend){
$gallery.append(imgsToAppend);
}
$gallery.unitegallery();
}
});
});
This solved the problem. Thanks for the help anyway.
You make a ajax request to the folder wich contains your images? is there a index.php or a index.html wich retruns you a html?
You have some useless additional quotes in your .append argument, try with this :
$("#gallery").append("<img alt='uploaded file' src='" + folder + val + "' data-image='" + folder + val + "' data-description='uploaded file by user'>");
And do a console.log(data) after the ajax response, if you have nothing, add the error calback to your ajax function and console.log the error, or see the response in your browser console in the network tab
EDIT
I think that the jQuery .find function doesn't accept any callback arguments, you would use the .each function:
var $gallery = $("#gallery");
$(data).find("a").each(function(i, el) {
var val = $(el).attr('href');
if (val.match(/\.(jpe?g|png|gif)$/)) {
$gallery.append("<img alt='uploaded file' src='" + folder + val + "' data-image='" + folder + val + "' data-description='uploaded file by user'>");
}
});

URL Name not resolved in Jquery

I am trying to dynamically build up HTML using JQuery in ASP.NET MVC5. I have so far had success, but the URL cannot be resolved in the JQuery Code.
My code looks something like this:
$.ajax({
type: 'POST',
url: '#Url.Action("QuerySearch")',
dataType: 'json',
data: {
queryName: $("#queryText").val()
},
success: function (data) {
// var items = '';
$.each(data, function (i, item) {
var resource_Url = item.ResourceURL;
// var resource_url = item.ResourceURL;
var append_data = $('<div class="row">'
+ '<h3>' + item.ResourceTitle + '</h3>'
+ '</div>'
+ '<div class="row">'
+ '<span class="label label-primary" style="margin:3px;font-size:small;">'
+ item.ResourceEducation
+ '</span>'
+ '<span class="label label-warning" style="margin:3px;font-size:small;">'
+ item.ResourceGrades
+ '</span>'
+ '<span class="label label-info" style="margin:3px;font-size:small;">'
+ item.ResourceSubject
+ '</span>'
+ '<a href="#Url.Content("' + item.ResourceURL + '")">'
+ '<img src="#Url.Content("~/Content/Resources/download_icon.png")" alt="Download Resource" style="height:24px;width:24px;"/>'
+ '</a>'
Although this code is able to retrieve the image for the download_icon defined in my project, it is not able to display / embed the URL fetched from the server by my function which I am trying to display in the <a href> tag.
Any help is greatly appreciated.
You will need to pass the complete url value from the server as a property of the data received. Or have it stored locally
ASP code doesn't run in the browser, only on server
The trick was simple, the href tag had to be changed to:
'<a href="' + item.ResourceURL + '">'
It worked like a charm

jQuery Autocomplete Nested Ajax Calls

I am currently working on implementing an album search autocomplete using the Spotify Metadata API. I have most of the features complete, but I am having trouble when doing a nested call to retrieve the album cover art. Here I believe is the root of my problem. When I do the ajax call to retrieve the image it does work, and I get the right data, but the return statement is not getting executed. What I am trying to do is get the first four results, for each get an image and return the label, item and image.
$('#spotify-album-search').autocomplete({
source:
function (query, process) {
$.when(
$.ajax({
url: 'http://ws.spotify.com/search/1/album.json?q=' + query.term,
})
).then(function (data) {
process($.map(data.albums.slice(0, 4), function(item) {
$.when (
$.ajax({
url: 'https://embed.spotify.com/oembed/?url=' + item.href,
dataType: 'jsonp'
})
).then(function (image) {
// Input: The Rolling Stones
console.log(item.artists[0].name + ' - ' + item.name + ': ' + image.thumbnail_url);
// Console: The Rolling Stones - Let It Bleed: https://d3rt1990lpmkn.cloudfront.net/cover/91205a1c80960d7055f8ed1bbe022f195e1767a4
return { label: item.artists[0].name + ' - ' + item.name, album: item, image: image.thumbnail_url };
});
}));
});
},
select: function (e, ui) {
console.log("selected= " + ui.item.album);
},
messages: {
noResults: '',
results: function() {}
}
})
.data('ui-autocomplete')._renderItem = function(ul, item) {
return $('<li></li>')
.data( "ui-autocomplete-item", item)
.append('<a>' + item.label + '<img src="' + item.image + '" alt="" />' + '</a>')
.appendTo(ul);
};
EDIT:
Here you can find a working fiddle, if you believe could help!
http://jsfiddle.net/9GbkL/
In asynchronous programming, return is only useful for forcing an exit. You can't actually return data....
The only way to use data in asynchronous programming is to send it to a function.
So, you need a function that can update the UI given the data...
Add this functionality where currently the console.log testing with the data is done.
Thanks to the help from Godsbest at the jQuery Forums, I was able to get this working. Paul was right, and I needed the function call instead of the return statement. If anyone ever runs into a problem like I did, here is a fiddle with Autocomplete working with Bootstrap 3 and the Spotify Metadata API:
JS:
$('#spotify-album-search').autocomplete({
source:
function (query, process) {
$.when(
$.ajax({
url: 'http://ws.spotify.com/search/1/album.json?q=' + query.term,
})
).then(function (data) {
var process_data = [];
$.each(data.albums.slice(0, 4), function(i,item) {
$.when (
$.ajax({
url: 'https://embed.spotify.com/oembed/?url=' + item.href,
dataType: 'jsonp'
})
).then(function (image) {
process_data.push( { artist: item.artists[0].name, album_name: item.name, label: item.artists[0].name + ' - ' + item.name, album: item, href: item.href, image: image.thumbnail_url.replace("cover", "60")} );
process( process_data );
});
});
});
},
open: function(event, ui) {
},
select: function (e, ui) {
e.preventDefault();
$('#spotify-id').val(ui.item.album.href);
$(this).val(ui.item.label);
},
messages: {
noResults: '',
results: function() {}
}
})
.data('ui-autocomplete')._renderItem = function(ul, item) {
return $('<li>')
.data( "ui-autocomplete-item", item)
.append('<a>' + '<img width="50" src="' + item.image + '" alt="" />' + '<span class="ui-autocomplete-artist">' + item.artist + '</span>' + '<span class="ui-autocomplete-divider"><i class="fa fa-minus"></i></span>' + '<span class="ui-autocomplete-album-name">' + item.album_name + '</span>' + '<span class="ui-autocomplete-icon pull-right"><i class="fa fa-plus-circle fa-2x"></i></span>' + '</a>')
.appendTo(ul);
};
http://jsfiddle.net/9GbkL/5/ . Happy coding!

how to show the loader dynamically until all the image load in jquery mobile phonegap listview

am having trouble to showing loader untill all the image is load in the listview.the following code is used in my app.it shows the loader untill all the image is load but the problem is , append the last src value to all the image attribute src.please help me.
$.ajax({
url: "http://www.some.com/",
type: 'POST',
data: param,
dataType: "jsonp",
success: function (result) {
$.each(result.results, function (k, v) {
var searchPic = "http://www.some.com" + $.trim(v.eventIcon);
var localarray = new Array();
var c = v.eventText;
strs = c.slice(0, 60);
$('[data-role="listview"]').append('<li> ' + '<img alt="img" class="pic1" src=" ">' + '<h4 >' + v.eventTitle + '</h4>' + '<p>' + strs + '...' + '</p></li>');
$('[data-role="listview"]').listview('refresh');
imgload(searchPic);
});
$('[data-role="listview"]').append('<li id="no-results">There is no record found based on your search criteria, please refine your search.</li>');
}
});
function imgload(tx) {
$('.pic1').load(function () {
$.mobile.loading('hide');
}).attr('src', tx);
}
});

Non-functioning view when sharing controller

I have a simple app that fetches images from Flickr and renders them. The application is divided into two views, SearchView and PhotoListView. Previously, when treating these as one view, everything worked fine, and photos were rendered. Now, when sharing controller, both are rendered but the list of photos is never populated. When debugging I can see that the photos are indeed fetched.
I'm terribly new at Angular, so I really don't have any good guesses at what the problem could be, but possibly that the two views don't share scope properly?
Here's the routing (using ui-router):
// app.js
'use strict';
angular.module('pruApp', ['ui.state'])
.config(function ($httpProvider, $stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise('/photos');
$stateProvider
.state('/', {
url: '/photos',
views: {
'SearchView': {
templateUrl: '/views/search.html',
controller: 'PhotoCtrl'
},
'PhotoListView': {
templateUrl: '/views/photo-list.html',
controller: 'PhotoCtrl'
}
}
});
// Remove X-Requested-With header to enable CORS
delete $httpProvider.defaults.headers.common['X-Requested-With'];
});
The controller and factory that talks to the Flickr service:
// photo.js
'use strict';
angular.module('pruApp')
.controller('PhotoCtrl', function ($scope, PhotoFactory) {
$scope.search = function() {
PhotoFactory.getPhotos($scope.searchQuery).then(function (data) {
$scope.photos = [];
var parsedData = angular.fromJson(data);
var items = parsedData.photos.photo;
for (var i = 0; i < items.length; ++i) {
var photo = items[i];
$scope.photos.push({
title: photo.title,
image: 'http://farm' + photo.farm + '.staticflickr.com/' + photo.server + '/' + photo.id + '_' + photo.secret + '_m.jpg',
link: 'http://www.flickr.com/photos/' + photo.owner + '/' + photo.id
});
}
});
};
});
angular.module('pruApp')
.factory('PhotoFactory', function ($http, $q) {
return {
_get: function(url) {
var deferred = $q.defer();
$http.get(url)
.success(function (data) {
deferred.resolve(data);
})
.error(function (data, status) {
deferred.reject('An error occured: ' + status);
});
return deferred.promise;
},
getPhotos: function (searchQuery) {
return this._get('http://api.flickr.com/services/rest/?method=flickr.photos.search&api_key=<MY_KEY>&tags=' + searchQuery + '&format=json&nojsoncallback=1');
}
};
});
This is where the views are injected:
<!-- index.html -->
<div class="main" role="main">
<div class="search" ui-view="SearchView"></div>
<div class="results" ui-view="PhotoListView"></div>
</div>
Search template:
<!-- search.html -->
<h2 class="struct">Search</h2>
<form>
<fieldset>
<div class="cell">
<input type="search" name="search-query" class="search-query" placeholder="Search photos by tags (e.g. lolcat, rageface, bronie)" ng-model="searchQuery" required>
</div>
<div class="cell">
<button type="submit" name="search-button" class="search-button" ng-click="search()">Search</button>
</div>
</fieldset>
</form>
Photo list template:
<!-- photo-list.html -->
<h2 class="struct">Search results</h2>
<ul>
<li ng-repeat="photo in photos">
<h3>{{ photo.title }}</h3>
<img ng-src="{{ photo.image }}" alt="{{ photo.title }}">
<p class="author">Author: <span>{{ photo.author }}</span></p>
</li>
</ul>
So your problem seems to be that you are calling the method to get the photos on one instance of the controller but that doesn't share data with your other controller. On first read I had missed your factory definition, still the problem is the variable in scope on the controller is in a different instance.
The way you can handle this is by always returning a promise from the factory/service to the controller, the in the controller using the promise to assign the scope. This way if the service has data already available it will automatically populate in your controllers scope, and if not as soon as it comes available it can be populated.
Really it looks like you're doing what I'm saying in the paragraph above but I don't see where the search function is called within the controller. Essentially you should just have something in the controller that is populating the $scope.photos array directly off the service. Then separately you should have your search function which fires off the call to the service passing along the parameter.
Another option is to $watch your properties in the factory/service and update a variable in the $scope of the controller on changes.
angular.module('pruApp')
.factory('PhotoFactory', function ($http, $q) {
return {
photos: [],
_get: function(url) {
var deferred = $q.defer();
$http.get(url)
.success(function (data) {
this.photos = [];
var parsedData = angular.fromJson(data);
var items = parsedData.photos.photo;
for (var i = 0; i < items.length; ++i) {
var photo = items[i];
this.photos.push({
title: photo.title,
image: 'http://farm' + photo.farm + '.staticflickr.com/' + photo.server + '/' + photo.id + '_' + photo.secret + '_m.jpg',
link: 'http://www.flickr.com/photos/' + photo.owner + '/' + photo.id
});
}
deferred.resolve(data);
})
.error(function (data, status) {
deferred.reject('An error occured: ' + status);
});
return deferred.promise;
},
getPhotos: function (searchQuery) {
return this._get('http://api.flickr.com/services/rest/?method=flickr.photos.search&api_key=<MY_KEY>&tags=' + searchQuery + '&format=json&nojsoncallback=1');
}
};
});
and in the controller
angular.module('pruApp')
.controller('PhotoCtrl', function ($scope, PhotoFactory) {
$scope.$watch(function () { return PhotoFactory.photos; }, function(data) {
$scope.photos = data;
}); // initialize the watch
$scope.search = function() {
PhotoFactory.getPhotos($scope.searchQuery);
};
}
});

Categories

Resources