I'm trying to display the results from a submitted form, AngularJS > PHP > Back but I'm getting nothing. I've tried a lot of different ways and according to all of google I'm doing it right but the console log just says that it's undefined.
Here is the submit function:
$scope.testProcessForm = function() {
$http({
method : 'POST',
url : 'test.php',
data : $scope.formData,
headers : {'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8'}
})
.success(function(data) {
if (data.errors) {
// Showing errors.
$scope.errorselectedServices = data.errors.selectedservices;
$scope.errorincEmail = data.errors.incemail;
} else {
$scope.submissionMessage = data.messageSuccess;
$scope.test= data.test;
The PHP:
$data['test'] = $test;
echo json_encode($data);
HTML:
<div ng-show="test">{{test}}</div>
Why am I getting "test is undefined" and no div? If I put an echo into PHP I get the proper reply back. It doesn't appear to hang anywhere in the code after some debugging. What am I doing wrong?
// app.js
// create our angular app and inject ngAnimate and ui-router
// =============================================================================
angular.module('formApp', ['ngAnimate', 'ngMessages', 'ui.router'])
// configuring our routes
// =============================================================================
.config(function ($stateProvider, $urlRouterProvider) {
$stateProvider
// route to show our basic form (/form)
.state('form', {
url: '/form',
templateUrl: 'form.html',
controller: 'formController'
})
// nested states
// each of these sections will have their own view
// url will be nested (/form/profile)
.state('form.tjanst', {
url: '/tjanst',
templateUrl: 'form-tjanster.html'
})
// url will be /form/interests
.state('form.epost', {
url: '/epost',
templateUrl: 'form-epost.html'
})
// url will be /form/payment
.state('form.fax', {
url: '/fax',
templateUrl: 'form-fax.html'
})
// url will be /form/payment
.state('form.sms', {
url: '/sms',
templateUrl: 'form-sms.html'
})
// url will be /form/payment
.state('form.mcl', {
url: '/mcl',
templateUrl: 'form-mcl.html'
})
// url will be /form/payment
.state('form.review', {
url: '/review',
templateUrl: 'form-review.html'
});
// catch all route
// send users to the form page
$urlRouterProvider.otherwise('/form/tjanst');
})
.value('formSteps', [
{uiSref: 'form.tjanst', valid: false},
{uiSref: 'form.epost', valid: false},
{uiSref: 'form.fax', valid: false},
{uiSref: 'form.sms', valid: false},
{uiSref: 'form.mcl', valid: false},
{uiSref: 'form.review', valid: false}
])
.run([
'$rootScope',
'$state',
'formSteps',
function($rootScope, $state, formSteps) {
// Register listener to watch route changes
$rootScope.$on('$stateChangeStart', function(event, toState, toParams, fromState, fromParams) {
var canGoToStep = false;
// only go to next if previous is valid
var toStateIndex = _.findIndex(formSteps, function(formStep) {
return formStep.uiSref === toState.name;
});
console.log('toStateIndex',toStateIndex)
if(toStateIndex === 0) {
canGoToStep = true;
} else {
canGoToStep = formSteps[toStateIndex - 1].valid;
}
console.log('canGoToStep', toState.name, canGoToStep);
// Stop state changing if the previous state is invalid
if(!canGoToStep) {
// Abort going to step
event.preventDefault();
}
});
}
])
// our controller for the form
// =============================================================================
.controller('formController', function($scope, $state, $http, formSteps) {
// we will store all of our form data in this object
$scope.formData = {};
$scope.submission = false;
$scope.formStepSubmitted=false;
$scope.formData.selectedServices = {};
$scope.messitServices = [{'name':'Fax', 'id':1}, {'name':'SMS', 'id':2}, {'name':'Minicall', 'id':3}];
$scope.someSelected = function (object) {
return Object.keys(object).some(function (key) {
return object[key];
});
};
var nextState=function(currentState) {
switch (currentState) {
case 'form.tjanst':
return 'form.epost'
break;
case 'form.epost':
return 'form.fax'
break;
case 'form.fax':
return 'form.sms'
break;
case 'form.sms':
return 'form.mcl'
break;
case 'form.mcl':
return 'form.review'
break;
default:
alert('Did not match any switch');
}
};
var updateValidityOfCurrentStep=function(updatedValidity) {
var currentStateIndex = _.findIndex(formSteps, function(formStep) {
return formStep.uiSref === $state.current.name;
});
formSteps[currentStateIndex].valid = updatedValidity;
};
$scope.goToNextSection=function(isFormValid) {
console.log('isFormValid ', isFormValid);
// set to true to show all error messages (if there are any)
$scope.formStepSubmitted = true;
if(isFormValid) {
// reset this for next form
$scope.formStepSubmitted = false;
// mark the step as valid so we can navigate to it via the links
updateValidityOfCurrentStep(true /*valid */);
$state.go(nextState($state.current.name));
} else {
// mark the step as valid so we can navigate to it via the links
updateValidityOfCurrentStep(false /*not valid */);
}
};
$scope.testProcessForm = function() {
$http({
method : 'POST',
url : 'kundreg.php',
data : $scope.formData,
headers : {'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8'}
})
.success(function(data) {
if (data.errors) {
// Showing errors.
$scope.errorselectedServices = data.errors.selectedservices;
$scope.errorincEmail = data.errors.incemail;
} else {
$scope.submissionMessage = data.messageSuccess;
$scope.faxSenderPhoneNo = data.faxSenderPhoneNo;
$scope.faxSender = data.messit.faxSender;
console.log(faxSender);
// $scope.formData = {};
}
});
};
});
<!DOCTYPE html>
<h3 class="text-center">Granskning</h3>
<h4 class="text-center">Vänligen kontrollera:</h4><br>
<div class="form-group row"></div>
<!-- <span ng-show="errorselectedServices">{{errorselectedServices}}</span>
<span ng-show="errorincEmail">{{errorincEmail}}</span>></div> -->
<div ng-show="faxSender">{{ faxSender }} ng show faxsenderphoneno</div>
<br>
<div class="form-group row">
<div class="col-xs-6 col-xs-pull">
<a ui-sref="form.fax" class="btn btn-block btn-info">
Föregående <span class="glyphicon glyphicon-circle-arrow-left"></span></a>
</div>
<div class="col-xs-6 col-xs-push">
<a ng-click="testProcessForm()">
Skapa <span class="glyphicon glyphicon-circle-arrow-right"></span>
</a>
</div>
</div>
<?php
$errors = array();
$data = array();
$selectedServices = array();
// Getting posted data and decodeing json
$_POST = json_decode(file_get_contents('php://input'), true);
// checking for blank values.
if (empty($_POST['selectedServices']))
$errors['selectedServices'] = 'Minst en tjänst måste väljas.';
if (empty($_POST['incEmail']))
$errors['incEmail'] = 'Epost som tillåts använda tjänsterna saknas';
$selectedServices = $_POST['selectedServices'];
if (!empty($errors)) {
$data['errors'] = $errors;
} else {
if (!empty($_POST["faxSenderPhoneNo"])) {
// ta bort allt som inte är siffror
$faxSender = preg_replace('/[^0-9\/+]/', '', $_POST["faxSenderPhoneNo"]);
// finns ingen nolla så lägger vi till den så vi kan matcha den i regexen
//regex med internationellt format så databasen blir glad
if (preg_match('/^0/', $faxSender) === 0) {
$faxSender = "0{$faxSender}";
}
$faxSenderPhoneNo = preg_replace("/(^0|^46)/", "+46", $faxSender);
$messit['faxSender'] = $faxSenderPhoneNo;
}
else {
$faxSenderPhoneNo = 'NULL';
}
if (!empty($_POST["deliveryReportFax"])) {
$deliveryReportFax = $_POST["deliveryReportFax"];
}
else {
$deliveryReportFax = '3';
}
}
}
if (!$error) {
// sql
echo json_encode($data);
?>
I found the error. Apparently you have to quote the variable into the array;
$data['faxSender'] = "$faxSenderPhoneNo";
Now works as intended.
EDIT:
Well it worked to a point. My divs still weren't displaying. After logging with console.log(data) I could see that I had a lot of undefined indexes but my data array was there so I didn't understand why I couldn't access it.
I fixed the undefined stuff and then suddenly every div was displayed. Not a clue why PHP decides to dump all that info into my $data array.
2nd edit: Apparently .success is deprecated. Using .then instead with error_reporting(1); seems to always give me an array with data that angular then can use.
Since you are JSON encoding data in php file, file returning a String. so, you will need decode JSON to Java script object first. Also, you $http returns angular promise($q service). I am not sure about using
.success
method. Instead use
.then
.then(function successCallback(response) {
// this callback will be called asynchronously
// when the response is available
// decode JSON firs since you are sending JSON from PHP
var data = JSON.parse(response);
$scope.test = data.test;
}, function errorCallback(response) {
// called asynchronously if an error occurs
// or server returns response with an error status.
// Handle error here
});
Related
Hi guy i'm very new in angularjs and ionic.
I need to show the get json into html page.
How i can do that?
custom_fields: {
main_image: [
"11104,11102,11103"
],
image_backgrounds: [
null
],
videos_backgrounds: [
null
],
frontpage_listing_categories: [
null
],
geolocation_lat: [
"46.4090966"
],
This is my json return request.
How i can show on html for example : geolocation_lat?
I try to read documentation but i not understand.
Thank you
UPDATE:
HTML
<ion-view title="{{post.title}}">
<ion-nav-buttons side="right">
<a class="button button-clear" ng-click="sharePost()"><i class="icon ion-share"></i></a>
</ion-nav-buttons>
<ion-content class="has-header">
<div class="padding">
<h2 class="title">{{post.title}}</h2>
<div style="padding:0 0 20px 0;">
<!-- Posted {{post.date}} by <strong>{{post.author.name}}</strong><br/> -->
<!-- <em>Modified {{post.modified}}</em> -->
</div>
<p ng-show="{{post.attachments.length}}"><img ng-src="{{post.attachments[0].images.full.url}}"/></p>
<p ng-bind-html="content"></p>
<p ng-show="{{post.categories.length}}"><i class="icon ion-pricetags"></i>
<span ng-repeat="category in post.categories">{{category.title}} ({{category.post_count}}){{$last ? '' : ', '}}</span>
</p>
<p ng-show="{{post.tags.length}}"><i class="icon ion-pricetags"></i>
<span ng-repeat="tag in post.tags">{{tag.title}} ({{tag.post_count}}){{$last ? '' : ', '}}</span>
</p>
<p><button class="button icon-left ion-share button-outline button-positive" ng-click="sharePost()">Share this</button></p>
<!-- <button class="button button-full button-positive" ng-click="loadURL(post.url)">
View post
</button> -->
</div>
</ion-content>
APP.JS
.factory('PostsData', function($http, $q, PostsStorage, API) {
var json = API + '/api/get_recent_posts/';
var deferred = $q.defer();
var promise = deferred.promise;
var data = [];
var service = {};
service.async = function() {
$http({method: 'GET', url: json, timeout: 5000}).
// this callback will be called asynchronously
// when the response is available.
success(function(d) {
data = d;
PostsStorage.save(data);
deferred.resolve();
}).
// called asynchronously if an error occurs
// or server returns response with an error status.
error(function() {
data = PostsStorage.all();
deferred.reject();
});
return promise;
};
service.getAll = function() { return data; };
service.get = function(postId) { return data.posts[postId]; };
return service;
})
.factory('ServerPostsData', function($http, $q, ServerPostsStorage, API) {
var data = [];
var service = {};
/* (For DEMO purposes) Local JSON data */
// var json = 'json/serverposts&';
/* Set your URL as you can see in the following example */
/* NOTE: In case of the default permalinks, you should add '&' at the end of the url */
// var json = 'YourWordpressURL/?json=get_recent_posts&';
/* With user-friendly permalinks configured */
/* NOTE: In case of the user-friendly permalinks, you should add '?' at the end of the url */
var json = API + '/api/jobs/get_job_listing?';
service.getURL = function() { return json; };
service.setData = function(posts) { data = posts; };
service.get = function(serverpostId) { return data[serverpostId]; };
return service;
})
COTROLLER.JS
// ServerPosts Controller
.controller('ServerPostsCtrl', function($scope, $http, $ionicLoading, ServerPostsData, ServerPostsStorage) {
var data = []
$scope.posts = [];
$scope.storage = '';
$scope.loading = $ionicLoading.show({
template: '<i class="icon ion-loading-c"></i> Loading Data',
//Will a dark overlay or backdrop cover the entire view
showBackdrop: false,
// The delay in showing the indicator
showDelay: 10
});
$scope.loadData = function () {
$http({method: 'GET', url: ServerPostsData.getURL() + 'page=' + $scope.page, timeout: 5000}).
// this callback will be called asynchronously
// when the response is available.
success(function(data) {
$scope.more = data.pages !== $scope.page;
$scope.posts = $scope.posts.concat(data.posts);
ServerPostsData.setData($scope.posts);
ServerPostsStorage.save(data);
$ionicLoading.hide();
}).
// called asynchronously if an error occurs
// or server returns response with an error status.
error(function() {
$scope.posts = ServerPostsStorage.all().posts;
ServerPostsData.setData(ServerPostsStorage.all().posts);
$scope.storage = 'Data from local storage';
$ionicLoading.hide();
});
};
$scope.showMoreItems = function () {
$scope.page += 1;
$ionicLoading.show({
template: '<i class="icon ion-loading-c"></i> Loading Data',
//Will a dark overlay or backdrop cover the entire view
showBackdrop: false,
// The delay in showing the indicator
showDelay: 10
});
$scope.loadData();
}
$scope.hasMoreItems = function () {
return $scope.more;
}
$scope.page = 1;
$scope.more = true;
$scope.loadData();
})
// ServerPost Controller
.controller('ServerPostCtrl', function($scope, $stateParams, ServerPostsData, $sce) {
$scope.post = ServerPostsData.get($stateParams.serverpostId);
$scope.content = $sce.trustAsHtml($scope.post.content);
$scope.loadURL = function (url) {
//target: The target in which to load the URL, an optional parameter that defaults to _self. (String)
//_self: Opens in the Cordova WebView if the URL is in the white list, otherwise it opens in the InAppBrowser.
//_blank: Opens in the InAppBrowser.
//_system: Opens in the system's web browser.
window.open(url,'_blank');
}
$scope.sharePost = function () {
var subject = $scope.post.title;
var message = $scope.post.content;
message = message.replace(/(<([^>]+)>)/ig,"");
var link = $scope.post.url;
//Documentation: https://github.com/EddyVerbruggen/SocialSharing-PhoneGap-Plugin
//window.plugins.socialsharing.share('Message', 'Subject', 'Image', 'Link');
window.plugins.socialsharing.share(message, subject, null, link);
}
})
I've a following controller code with me :
var app = angular.module('app_name');
app.controller("manageUsersController", [ "config", "$scope", "$http", "$mdToast",
function(config, $scope, $http, $mdToast) {
$scope.add = function() {
var userData = {
email : $scope.manageUsers.email,
password : $scope.manageUsers.password,
schoolId : '1',
name : $scope.manageUsers.name,
mobileNumber : $scope.manageUsers.mobileNumber
};
$http.post(config.webServicesUrl.postAddUser, userData, headerConfig).success(
function(data) {
displayToastMessage("User added successfully", $mdToast);
}).error(function(error) {
console.log(error.error);
});
}
}]);
All the HTML fields are input fields and are accessed using $scope object.
I tried with $setPristine but it didn't work.
Somebody please help me in setting all the fields to empty upon successful submission of form only in my code.
Thanks.
If you want to reset your form upon completion, I think you have to reset the $scope.manageUsers object manually once your post request has resolve:
$http.post(config.webServicesUrl.postAddUser, userData, headerConfig).success(
function(data) {
// has I don't know if you have other properties
// I reset each property manually,
// but you could probably do $scope.manageUsers = {}
$scope.manageUsers.email = null;
$scope.manageUsers.password = null;
$scope.manageUsers.name = null;
$scope.manageUsers.mobileNumber = null;
displayToastMessage("User added successfully", $mdToast);
}).error(function(error) {
console.log(error.error);
});
You can use $setPristine() here:
$http.post(config.webServicesUrl.postAddUser, userData, headerConfig).success(
function(data) {
displayToastMessage("User added successfully", $mdToast);
$scope.form.$setPristine(); // <---------here.
}).error(function(error) {
console.log(error.error);
});
Plnkr demo in action.
It should work for you.
$http.post(config.webServicesUrl.postAddUser,userData,headerConfig)
.success(function(data) {
$scope.manageUsers={};
displayToastMessage("User added successfully.", $mdToast);
}).error(function(error) {
console.log(error.error);
});
I am calling two functions on ng-click. But it doesn't work. I am not sure why the Refresh1() is not called when I cross-checked through debugger.
HTML CODE
<div class="row" ng-controller="PublishManifestCtrl">
<div class="col-xs-12 col-md-12">
<div class="widget">
<div class="widget-header bordered-bottom bordered-themeprimary">
<i class="widget-icon fa fa-tasks themeprimary"></i>
<span class="widget-caption themeprimary">Manifest Status</span>
</div>
<div class="widget-body">
<form class="form-bordered" role="form">
<div class="form-group">
<label style="padding-left: 8px;">Manifest was last published to agents on <b>{{manifeststatus.manifestLastPublishedDate}}</b>.</label>
</div>
<div class="form-group">
<label style="padding-left: 8px;">Manifest was last updated by <b> {{manifeststatus.lastUpdatedByUser}} </b> on <b>{{manifeststatus.manifestLastedUpdatedDate}}</b>.</label>
</div>
<div class="form-group">
<div class="col-sm-offset-1">
**<button id="PublishButton" class="btn btn-default shiny " ng-disabled="manifeststatus.enablePublishButton" ng-click="Save(manifeststatus);Refresh1()">Publish</button>**
</div>
<br/>
<div id="statusDivPublish" ng-show="showstatus">
<alert type="{{alert.type}}">{{alert.msg}}</alert>
</div>
</div>
</form>
</div>
JSFILE
$scope.Save = function (data) {
debugger;
$http.post($rootScope.WebApiURL + '/updatemanifeststatus');
//$http.get({ url: $rootScope.WebApiURL + '/getmanifeststatus' });
$scope.manifeststatus = data;
$scope.showstatus = true;
$scope.alert = { type: 'success', msg: 'Published Successfully.' };
$(".statusDivPublish").show();
}
$scope.Refresh1 = function () {
//refresh
$state.transitionTo($state.current, $stateParams, {
reload: true,
inherit: false,
notify: true
});
}
});
new code
$scope.Save = function (data) {
debugger;
$http.post($rootScope.WebApiURL + '/updatemanifeststatus');
//$http.get({ url: $rootScope.WebApiURL + '/getmanifeststatus' });
$scope.manifeststatus = data;
$scope.showstatus = true;
$scope.alert = { type: 'success', msg: 'Published Successfully.' };
$(".statusDivPublish").show();
$scope.Refresh1();
}
$scope.Refresh1 = function ($rootScope, $state, $stateParams) {
debugger;
return {
restrict: 'AC',
link: function (scope, el, attr) {
el.on('click', function () {
$state.transitionTo($state.current, $stateParams, {
reload: true,
inherit: false,
notify: true
});
});
}
};
};
});
The first one updates and displays a successfull message, while the second function refreshes the page.
use this
$scope.Save = function (data) {
debugger;
$http.post($rootScope.WebApiURL + '/updatemanifeststatus');
//$http.get({ url: $rootScope.WebApiURL + '/getmanifeststatus' });
$scope.manifeststatus = data;
$scope.showstatus = true;
$scope.alert = { type: 'success', msg: 'Published Successfully.' };
$(".statusDivPublish").show();
$scope.refresh();
}
call refresh inside the first function and remove it from the ng-click.
Update
You have a different type of problem i had it too. you try to refresh a state inside a method, it's really difficult i solve that problem with this snippet
if($state.current.name == /*name of the current state*/) {
$state.go($state.current, {}, {reload: true});
$modalInstance.close();
}
else {
$modalInstance.close();
$state.go(/*name of the current state*/);
}
it's not difficult but it didn't behave like you have understand it.
UPDATE
taking your code
$scope.Refresh1 = function () {
//refresh
$state.go($state.current, {}, {reload: true});
}
What about calling refresh inside of save in $http handler ?
Like this:
$http.post($rootScope.WebApiURL + '/updatemanifeststatus')
.then(function(){
$scope.Refresh1();
});
Don't execute two function in one ng-click, instead add the Refresh1 call to the end of the Save call, like so.
HTML
<button id="PublishButton"
class="btn btn-default shiny "
ng-disabled="manifeststatus.enablePublishButton"
ng-click="Save(manifeststatus)">Publish</button>
JS
$scope.Save = function (data) {
debugger;
$http.post($rootScope.WebApiURL + '/updatemanifeststatus');
//$http.get({ url: $rootScope.WebApiURL + '/getmanifeststatus' });
$scope.manifeststatus = data;
$scope.showstatus = true;
$scope.alert = { type: 'success', msg: 'Published Successfully.' };
$(".statusDivPublish").show();
$scope.refresh();
}
Update
If you are using AngularJS V1.2.2 or higher, then using ui-router, the following should work to reload the data.
$state.transitionTo($state.current, $stateParams, {
reload: true,
inherit: false,
notify: true
});
The shortest way to accomplish this though would be with:
$state.go($state.current, {}, {reload: true}); //second parameter is for $stateParams
Its also worth noting that none of these will actually reload the page. If you want to reload the state AND the page, there is no ui-routermethod for it. Do window.location.reload(true)
Update 2
If you are receiving:
$state is not defined at Scope.$scope.Refresh1
(publishmanifest.js:44) at Scope.$scope.Save (publishmanifest.js:37)
at $parseFunctionCall (angular.js:12345) at angular-touch.js:472 at
Scope.$eval (angular.js:14401) at Scope.$apply (angular.js:14500) at
HTMLButtonElement. (angular-touch.js:471) at
HTMLButtonElement.n.event.dispatch (jquery.min.js:3) at
HTMLButtonElement.r.handle (jquery.min.js:3)
You are not injecting the $state service in your controller. You must do this in order to use it.
//without annotation (inferred, not safe when minifying code)
function Controller($scope, $state) {...}
//inline annotation
module.controller('Controller', ['$scope','$state', function($scope, $state) {...}]);
//$inject property annotation
function Controller($scope, $state) {...}
Controller.$inject = ['$scope', '$state'];
Pick one of the methods above to setup your controller to use $state.
Just make a third function like:
function3(data) {
save(data);
refresh1();
}
I have a custom directive for soundcloud that requires the soundcloud url. The soundcloud url is fetched from the database through the $http service, however, the div for the soundcloud custom directive is loaded and requires the value of the soundcloud url before it is even defined.
The Plangular Directive Code I got is here:
https://github.com/jxnblk/plangular/blob/master/src/plangular.js *I did not develop this
This is my HTML code:
<div plangular="{{soundcloud}}">
<button ng-click="playPause()">Play/Pause</button>
<progress ng-value="currentTime / duration || 0">
{{ currentTime / duration || 0 }}
</progress>
</div>
And this is the Angular Code:
displaySong.controller('song', ['$scope', '$http', 'fetchSong', function($scope, $http, fetchSong) {
$scope.songID
$scope.songName;
//Controller properties
$scope.songPromise; //The song promise for fetching
$scope.init = function(songID, userID) {
$scope.songID = songID;
$scope.userID = userID;
$scope.songPromise = $http({
method: "post",
url: fetchSong,
data: {
song_id: $scope.songID
},
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
}).then(function(successResponse) {
console.log('Successfully fetched song');
console.log(successResponse);
var song = successResponse.data;
$scope.songID = song.song_id;
$scope.songName = song.song_name;
$scope.songType = song.song_type;
$scope.songEmbed = song.song_embed;
$scope.soundcloud = song.song_embed;
}, function(errorResponse) {
console.log('Error fetching');
$scope.songID = null;
});
};
}]);
I know it's a problem with the asynchronous nature because when I add this line in the beginning of my song controller:
$scope.soundcloud = "https://soundcloud.com/jshigley/shine";
It works perfectly fine. I've also noticed that when I spam the play/pause button that DOES come up from the directive, I get multiple console errors of "HTTP 404 Not Found", which leads me to believe it's trying to find a track of undefined url
Since it's a div directive and not a function call I can't use promises such as chaining a then to my $scope.songPromise. I've thought of putting it into a controller and having the controller do something like $timeout for 5 seconds, but I don't think this delays the execution of the DOM.
The soundcloud URL DOES end up getting loaded, but it remains undefined in the eyes of the plangular directive (I've actually encountered lots of these problems with bad timing of loading scope and directives). Any Angular Wizards willing to teach me how to tame the asynchronous nature of AngularJS?
You can use $watch in the custom directive to watch when url attributes is changed.
In
link: function(scope, el, attr) {
change from
if (src) {
resolve({ url: src, client_id: client_id }, function(err, res) {
if (err) { console.error(err); }
scope.$apply(function() {
scope.track = createSrc(res);
if (Array.isArray(res)) {
scope.tracks = res.map(function(track) {
return createSrc(track);
});
} else if (res.tracks) {
scope.playlist = res;
scope.tracks = res.tracks.map(function(track) {
return createSrc(track);
});
}
});
});
}
to
scope.$watch('attr.plangular', function(newVal) {
resolve({ url: attr.plangular, client_id: client_id }, function(err, res) {
if (err) { console.error(err); }
scope.$apply(function() {
scope.track = createSrc(res);
if (Array.isArray(res)) {
scope.tracks = res.map(function(track) {
return createSrc(track);
});
} else if (res.tracks) {
scope.playlist = res;
scope.tracks = res.tracks.map(function(track) {
return createSrc(track);
});
}
});
});
}, true);
If you dont want to change the directive then you might want to use ng-if to load that plangular div only when you get the url.
<div plangular="{{soundcloud}}" ng-if="haveurl">
and in the angular code :
}).then(function(successResponse) {
console.log('Successfully fetched song');
console.log(successResponse);
$scope.haveurl = true;
Try using ng-show like this to only show the div once your $http request has been completed.
<div ng-show="httpRequestComplete" plangular="{{soundcloud}}">
<button ng-click="playPause()">Play/Pause</button>
<progress ng-value="currentTime / duration || 0">
{{ currentTime / duration || 0 }}
</progress>
</div>
displaySong.controller('song', ['$scope', '$q', '$http', 'fetchSong', function($scope, $http, fetchSong) {
/* add $q promise library */
$scope.songID
$scope.songName;
var httpRequest = function() {
var deferred = $q.defer();
$http({
method: "post",
url: fetchSong,
data: {
song_id: $scope.songID
},
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
}).success(function(successResponse) {
deferred.resolve({response: successResponse});
console.log('Successfully fetched song', successResponse);
var song = successResponse.data;
$scope.songID = song.song_id;
$scope.songName = song.song_name;
$scope.songType = song.song_type;
$scope.songEmbed = song.song_embed;
$scope.soundcloud = song.song_embed;
}).error(function(error) {
console.log(error);
});
return deferred.promise;
};
httpRequest().then(function(response) {
$scope.httpRequestComplete = true;
console.log('div will show');
};
}]);
I would do something like this that delays the showing of the div until httpRequestComplete = true, or until your promise ($q) is fulfilled. This will make sure that your div isn't loaded until you have the information available.
Currently I am working on my master project. My application is online portfolio management. User can register on app and create profiles. Now i want to give Edit and Delete buttons on the profile view. But just the users who have created the profile are able to see this buttons. For example, if i am a user of app then only i can see the edit and delete buttons on my profile and i can only see the other user's profile.
I am new in AngularJS. It looks easy but still did not work for me. I have a different views of view profile and edit profile. But i have just one controller for both of it.
This is how my view profile code looks like,
HTML
<section data-ng-controller="ProfilesController as profilesCtrl">
<div class="modal-header">
<div>
<h1>{{profile.firstname}} {{profile.lastname}}</h1>
</div>
<div class="pull-right">
<button class="btn-success btn-lg" type="button" data-ng-click="profilesCtrl.modalUpdate('lg', profile)">Edit</button>
<button class="btn-danger btn-lg" type="button" data-ng-click="profilesCtrl.remove(profile)">
<i class="glyphicon glyphicon-trash">
</i>
</button>
</div>
</div>
</section>
Controller
profilesApp.controller('ProfilesController', ['$scope', '$stateParams', '$location', 'Authentication', 'Profiles', '$modal', '$log',
function($scope, $stateParams, $location, Authentication, Profiles, $modal, $log) {
this.authentication = Authentication;
// Find a list of Profiles
this.profiles = Profiles.query();
// open a modal window to view single profile
this.modalview = function(size, selectedProfile) {
var modalInstance = $modal.open({
templateUrl: 'modules/profiles/views/view-profile.client.view.html',
controller: function($scope, $modalInstance, profile) {
$scope.profile = profile;
console.log(profile);
$scope.ok = function() {
$modalInstance.close($scope.profile);
};
},
size: size,
resolve: {
profile: function() {
return selectedProfile;
}
}
});
modalInstance.result.then(function(selectedItem) {
$scope.selected = selectedItem;
}, function() {
$log.info('Modal dismissed at: ' + new Date());
});
};
// open a modal window to update single profile
this.modalUpdate = function(size, selectedProfile) {
var modalInstance = $modal.open({
templateUrl: 'modules/profiles/views/edit-profile.client.view.html',
controller: function($scope, $modalInstance, profile) {
$scope.profile = profile;
$scope.ok = function() {
$modalInstance.close($scope.profile);
};
$scope.cancel = function() {
$modalInstance.dismiss('cancel');
};
},
size: size
});
modalInstance.result.then(function(selectedItem) {
$scope.selected = selectedItem;
}, function() {
$log.info('Modal dismissed at: ' + new Date());
});
};
// Remove existing Profile
this.remove = function(profile) {
if (profile) {
profile.$remove();
for (var i in this.profiles) {
if (this.profiles[i] === profile) {
this.profiles.splice(i, 1);
}
}
} else {
this.profile.$remove(function() {
$location.path('modules/profiles/views/list-profiles.client.view.html');
});
}
};
// Update existing Profile
this.update = function(updatedProfile) {
var profile = updatedProfile;
profile.$update(function() {}, function(errorResponse) {
$scope.error = errorResponse.data.message;
});
};
}
]);
Please suggest me some way, how can i fix this issue? Any help would appreciated.
you can use a directive like this:
<button access-level="canEdit">Edit</button>
and your directive is bound to accessLevel:
angular.module("app")
.directive('accessLevel', ['AuthService', 'AUTH_EVENTS', function (authService, authEvents) {
return {
restrict: 'A',
link: function ($scope, element, attrs) {
var accessLevel;
attrs.$observe('accessLevel', function (acl) {
if (acl) {
accessLevel = acl;
updateCss();
}
});
$scope.$on("auth-change", function (event, data) {
switch (data) {
case authEvents.logoutSuccess:
case authEvents.loginSuccess:
updateCss();
break;
case authEvents.notAuthorized:
default:
}
});
function updateCss() {
if (accessLevel) {
if (!authService.isAuthorized(accessLevel)) {
switch (element[0].nodeName) {
case "A":
element.hide();
break;
default:
element.attr("disabled", "disabled");
break;
}
} else {
switch (element[0].nodeName) {
case "A":
element.show();
break;
default:
element.removeAttr("disabled");
break;
}
}
}
}
}
}
}]);
this is a little bit more than what you need, but gives you an idea what you can achieve. (and you have to write your auth service etc.)
as example here is a part of my auth service:
angular.module('app')
.factory("AuthService", ["$rootScope", "$http", "AuthSession", "AUTH_EVENTS", function ($rootScope, $http, AuthSession, AUTH_EVENTS) {
AuthSession.load();
$rootScope.$on('$stateChangeStart', function (event, nextState) {
if (nextState.data && nextState.data.accessLevel && !service.isAuthorized(nextState.data.accessLevel)) {
event.preventDefault();
$rootScope.$broadcast('auth-change', AUTH_EVENTS.loginRequired, nextState.name);
}
});
var service = {
login: function (credentials) {
return $http
.post('/api/account/login', credentials)
.success(function (data, status) {
if ((status < 200 || status >= 300) && data.length >= 1) {
$rootScope.$broadcast("auth-change", AUTH_EVENTS.loginFailed);
return;
}
AuthSession.create(data.AccessToken, data.User);
$rootScope.$broadcast("auth-change", AUTH_EVENTS.loginSuccess);
}).error(function (data, status) {
$rootScope.$broadcast("auth-change", AUTH_EVENTS.loginFailed);
});
},
logout: function () {
AuthSession.destroy();
$rootScope.$broadcast("auth-change", AUTH_EVENTS.logoutSuccess);
},
isAuthenticated: function () {
return (AuthSession.token !== null);
},
isAuthorized: function (accessLevel) {
if (!accessLevel) return true;
return (this.isAuthenticated() && AuthSession.user.UserRoles.indexOf(accessLevel) !== -1);
}
}
return service;
}]);
this service retrieves a bearer token from the server and stores it in the authsession service. the user roles are also stored beside of other user information. since the backend is also secured, one who changes the user roles on the client, can't write to the backend. (everything on client side is just for the look and feel of the user)
Two ways :
Once the profile is created, let the isProfileCreated (you need to make one) column in user details table be updated. On angular load, call and check whether is profile created. use ng-show to show (edit and delete button)if it is true.
Or else, if you are going to edit, anyways you need to get the profile details from the table. in that case, let your server send a false if no profile is created or an json object if created.
In your controller use
if(angular.isObject(profile)){
$scope.showeditbutton = true;
$scope.showdeletebutton = true;
}