Angular View not updating after retrieving data from database - javascript

I am currently working on an app that retrieves data on the of change of $routeParams. So here's how it begins:
function artistCtrl($scope, $http, $location, dataFactory, $routeParams){
$scope.artistName = $routeParams.artistname
$scope.$watch('artistName', function(newValue, oldValue){
$scope.artistInfo = dataFactory.getArtist(newValue)
})
$scope.artistInfo = {
artist_name: dataFactory.artistInfo.artist_name,
artist_genre: dataFactory.artistInfo.artist_genre,
artist_imageurl: dataFactory.artistInfo.artist_imageurl,
artist_bio: dataFactory.artistInfo.artist_bio
};
}
The callback for $watch here is run. dataFactory.getArtist retrieves newValue from my database which is being done successfully. That is done like this:
dataFactory.js
dataFactory.getArtist = function(artist){
return dataFactory.checkDb(artist).then(function(dbData){
if(dbData.data != "No data"){
dataFactory.artistInfo = dbData.data[0]
}
return dbData.data[0]
})
}
dataFactory.artistInfo = "";
dataFactory is a factory I created in another file.
artistpage.html
<div class="container this">
<div class="row">
<div class="col-sm-6">
<div><h1>{{artistInfo.artist_name}}</h1></div>
<div rate-yo id='stars' rating="myRating" class="col-sm-4"></div>
<div id='reviews'>23 Reviews</div>
<div><h2>{{artistInfo.artist_genre}}</h2></div>
<div><p>{{artistInfo.artist_bio}}</p></div>
<div><button type="button" class="btn btn-primary" ng-click="somefunc()">Submit a Review</button></div>
</div>
<div class="col-sm-6 reviews">
<div><img class="artistpageimage" src={{artistInfo.artist_imageurl}}></div>
</div>
</div>
</div>
I don't understand why my view isn't being updated. I am attempting to update $scope.artistName by assigning the returned dataFactory.getArtist(newValue)
and also by assigning the new data to dataFactory.artistInfo I have read about $apply, but I am having a hard time figuring out how to apply it in this context. Can anyone help?

Does getArtist return a promise or a value. If it's a promise try something like the below:
$scope.$watch('artistName', function(newValue, oldValue){
dataFactory.getArtist(newValue).then(function(value) {
$scope.artistInfo = value;
})
})

I think the problem is that dataFactory.getArtist(newValue) is returning a promise, which you're assigning directly to artistInfo. Try replacing it with:
dataFactory.getArtist(newValue).then(function (info) {
$scope.artistInfo = info;
});

Related

How to avoid AngularJS ui grid showing 'no-data' message while api is loading

I have angularjs ui-grid, i used below condition to check availability of data, which means if data is not there i am showing 'no data available' message.
The problem is my api call is little slow because of huge data, so while this call in process no data available will show, I need to hide it in angular way initially. I cant use disply:none initially because there are so many conditions in grid filter after which that message will have to show, so every time i cant say disaply:none and display:block. Any help will be very helpful thank you.
html
<div ng-controller="MainCtrl">
<div ui-grid="gridOptions" ui-grid-selection ui-grid-exporter class="grid">
<div class="watermark" ng-show="!gridOptions.data.length">No data available</div>
</div>
</div>
Sample js call
$http.get('https://cdn.rawgit.com/angular-ui/ui-grid.info/gh-pages/data/100.json')
.success(function(data) {
data = {"data": []};
$scope.gridOptions.data = data;
});
Please see the demo in below plunker
Add a new variable in controller:
$scope.noData = false;
Change your api call as:
$http.get('https://cdn.rawgit.com/angular-ui/ui-grid.info/gh-pages/data/500.json')
.success(function(data) {
if (data.length > 0) {
$scope.gridOptions.data = data;
} else {
$scope.noData = true;
}
});
in the view change:
<div class="watermark" ng-show="noData">No data available</div>
Test Plunker
Easy doing by using another state handler variable e.g. $scope.loading:
<div ng-controller="MainCtrl">
<div ui-grid="gridOptions" ui-grid-selection ui-grid-exporter class="grid">
<div class="watermark"
ng-show="!gridOptions.data.length && !loading">No data available</div>
<div class="watermark"
ng-show="loading">loading ...</div>
</div>
</div>
Controller
$scope.loading = true;
$http.get('https://cdn.rawgit.com/angular-ui/ui-grid.info/gh-pages/data/100.json').success(function(data) {
$scope.loading = false;
data = {"data": []};
$scope.gridOptions.data = data;
});
1) plnkr Demo
2) plnkr Demo (inlcuding a little timeout)

Event in Angular Controller Only Fires Once

I'm trying to implement an Angular version of an autocomplete textbox. I found some working examples, but none seem to exhibit the behavior I'm getting.
The autocomplete functionality itself works fine. When a suggested item is selected, the control correctly handles the selection. Subsequent uses of the control (typing in the autocomplete box, making a selection) fail to engage the 'selected' event/condition, although the autocomplete bit continues to work.
Here's my module & controller:
var app = angular.module('myapp', ['angucomplete-alt']); //add angucomplete-alt dependency in app
app.controller('AutoCompleteController', ['$scope', '$http', function ($scope, $http) {
//reset users
$scope.Users = [];
$scope.SelectedUser = null;
//get data from the database
$http({
method: 'GET',
url: '/UserRoleAdministration/Autocomplete'
}).then(function (data) {
$scope.Users = data.data;
}, function () {
alert('Error');
})
//to fire when selection made
$scope.SelectedUser = function (selected) {
if (selected) {
$scope.SelectedUser = selected.originalObject;
}
}
}]);
I'm guessing the problem is in there, but I don't know what it is. I include the bit from my view below, although there doesn't seem to be much there to fuss with:
<div class="form-group">
<div ng-app="myapp" ng-controller="AutoCompleteController">
<div angucomplete-alt id="txtAutocomplete" pause="0" selected-object="SelectedUser" local-data="Users" search-fields="RegularName" placeholder="People Search" title-field="RegularName" minlength="2" input-class="form-control" match-class="highlight"></div>
<!--display selected user-->
<br /><br />
<div class="panel panel-default" id="panelResults">
<div class="panel-heading"><h3 class="panel-title">Manage Roles for {{SelectedUser.RegularName}}</h3></div>
<div class="panel-body">
<div class="row">
<div class="col-md-2">
<img src="~/Images/avatar_blank.png" width="100%" />
</div>
<div class="col-md-4">
<div class="row">
<div class="col-md-4">Selected User:</div> <div class="col-md-6">{{SelectedUser.RegularName}}</div>
</div>
</div>
</div>
</div>
</div>
</div>
Any help would be appreciated!
UPDATE
After fixing the mistake Yaser pointed out, I wasn't getting any information regarding the selected object. So I set the page to output the entire object, rather than the specified fields, and I noticed I was getting information about the selected object, and on subsequent attempts as well.
So this worked: {{SelectedUser}}
This did not: {{SelectedUser.Department}}
Then I looked at the object and noticed its format. It had "title" and "description", and description had inside it the key/value pairs.
So now this works: {{SelectedUser.description.Department}}
And that's it.
Because the first time you are setting $scope.SelectedUser as a function but inside that you are rewriting the same one with an object. so next time it is not a function any more, try to rename the function:
$scope.setUser = function (selected) {
if (selected) {
$scope.SelectedUser = selected.originalObject;
}
}

Angular JS === comparison not working

I am trying to compare the value passed from the url to a controller to a field in a json file.
galleryItem.html
<div class="filter-box">
<ul class="filter list-inline text-center" ng-repeat="gal in ParentData">
<li></li>
</ul>
</div>
<div class="container-fluid">
<div class="row">
<div class="portfolio-box" ng-repeat="x in data">
<div class="col-sm-4">
<div class="item-img-wrap">
<img ng-src={{x.url}} class="img-responsive" alt="">
<div class="item-img-overlay">
<a href={{x.url}} class="show-image">
<span></span>
</a>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
The updated controller:
controllers.controller('GalleryViewCtrl', function GalleryViewCtrl($scope, $http, $stateParams) {
$scope.pageName = '';
$scope.Description = '';
$scope.GalleryID = $stateParams.id;
$http.get('/data/galleryItems.json')
.then(function (response) { $scope.ParentData = response.data.galleries });
$http.get('/data/galleryItemImages.json')
.then(function (response) {
$scope.data = response.data.images.galleryIdentifier === $stateParams.id;
});
});
I verified the correct value is being passed in to the controller, the values are static and so is the data being passed from the json file. I placed an if statement to check for null as suggested as well. I removed it temporarily to reduce what I'm working with.
If I remove the === $stateParams.id i get all of the images returned and displayed correctly.
If I replace $stateParams.id with a value that I know is in the list (4 or '4') i do not get anything returned. I also tried the value for the last item in the list.
There are no errors (loading scripts, reading json etc.) and all of the values are correct when I'm debugging.
I am still new to this and there is so much documentation with different solutions it all gets very confusing. If anyone has any ideas they would be greatly appreciated.
You are loading data to the $scope.data when the ajax call returns some data. I am assuming your view code is calling the galleryFiltered even before that. May be try to add a null check before returning the value from the method.
$scope.galleryFiltered = function () {
if($scope.data!=null)
{
return $scope.data.galleryIdentifier === $scope.GalleryID;
}
return false;
};
Remember that $http service returns a promise so your $scope.data will be undefined (or holding current state) until $http.get('/data/galleryItemImages.json') will return a success callback function and assign new value to $scope.data from response.
If you'll run $scope.galleryFiltered() before promise gets resolved you will have $scope.data == undefined or whatever data is stored on $scope.data at the time or $scope.galleryFiltered() execution.

Angularjs, getting data from factory

I have a factory where i am trying to get data by $http service.
factory:
(function(){
angular
.module('projectApp')
.factory('weatherfactory', weatherfactory);
weatherfactory.$inject=['$http'];
function weatherfactory($http){
var cities=[
{name: "Łódź", link: "http://api.openweathermap.org/data/2.5/weather?q=Lodz,pl"},
{name: "Warszawa", link: "http://api.openweathermap.org/data/2.5/weather?q=Warszawa,pl"}
];
var weat={};
var service={
getCities: getCities,
GetWeather: _GetWeather
};
return service;
function _GetWeather(link){
$http.get(link).success(function(data){
weat=data;
});
return weat;
}
function getCities(){
return cities;
}
}
})();
In controller i call function from factory:
function weatherData(city){
sa.weather=weatherfactory.GetWeather(city);
sa.show=true;
}
View:
<div class="row">
<div class="col-md-8">
<select class="form-control" ng-model="sa.city">
<option ng-repeat="city in sa.cities" value="{{city.link}}">{{city.name}}</option>
</select>
</div>
<div class="col-md-4">
<button class="btn btn-primary" ng-click="sa.weatherData(sa.city)">Wybierz</button>
</div>
<div ng-if="sa.show">
{{sa.weather.name}}
</div>
</div>
It works but not correctly. I have to click button twice to show correct data.
When you make any server request you have to wait until the response is available in the callback function.
In your code you are right away returning from the function GetWeather so weat is empty for the first time. When you click the button second time the weather information is available by that time so you are able to see the weather information.
You have to do the below changes in your code.
Service change
function _GetWeather(link){
return $http.get(link);
}
Controller change
function weatherData(city){
weatherfactory.GetWeather(city).success(function (data) {
sa.weather = data;
sa.show = true;
});
}

Angular API calls and promises

I'm working on an angular app and having a difficult time with one seemly simple operation. Basically, I'm making a call to the soundcloud api, grabbing my tracks, then looping through those tracks and grabbing the iframe embed object, injecting that into the tracks object then sending that whole thing as a promise to be resolved and stored in a $scope.soundcloud object. Just fyi, the second SC call is necessary to generate the widget html. I wish it wasn't but it is hah.
This all happends as it should and i can see the object in $scope. My template picks up the initial data (main track data), and console.logging the object shows the track and embed data, but the template NEVER sees the embed data.
So, fundamentally, How do I get my template to see the embed data, so i can use it with a directive or ng-bind-html? Below is all my code, please ask if you need any more information! Thank you all very much.
HTML
<div class="track" ng-repeat="track in soundcloud.tracks">
<div class="front">
<img src="app/img/loading.gif" />
</div>
<div class="back" ng-bind-html="{{track.oembed}}">
</div>
</div>
Angular Service
getTracks: function(){
var deferred = $q.defer();
var promise = deferred.promise;
SC.get("/me/tracks", function(tracks){
$.each(tracks, function(k, v){
if(v.sharing != 'private'){
SC.oEmbed(v.uri, function(oembed){
v.oembed = $sce.trustAsHtml(oembed.html);
});
} else {
v.oembed = null;
}
});
deferred.resolve(tracks);
});
return $q.all({tracks: promise});
}
Angular Controller
.controller("GridCtrl", ['$scope', 'Soundcloud', function($scope, Soundcloud){
// Init the Soundcloud SDK config
Soundcloud.initialize();
// Get the tracks from soundcloud
Soundcloud.getTracks().then(function success(results){
// Store tracks in the $scope
$scope.soundcloud = results;
console.log(results);
});
}]);
Try creating a directive like this:
app.module('yourModule').directive('embedTrack', function() {
return function(scope, elem, attr) {
elem.replaceWith(scope.track.oembed);
};
});
You then use it like this:
<div class="track" ng-repeat="track in soundcloud.tracks">
<div class="front">
<img src="app/img/loading.gif" />
</div>
<div class="back">
<div embed-track></div>
</div>
</div>
In case you want to pass it as an attribute to the directive, you need to use attr.$observe to make sure you get the value after the interpolation.
<div embed-track={{ track.oembed }}></div>
The directive would then be:
app.module('yourModule').directive('embedTrack', function() {
return function(scope, elem, attr) {
attr.$observe('embedTrack', function(value) {
elem.replaceWith(value);
});
};
});

Categories

Resources