Angular function inside JavaScript function - javascript

I have defined an AngularJS dialog as follows in my angular-app.js:
angular.module('myAPP', ['ngMaterial']).controller('AppCtrl', function($scope, $mdDialog) {
$scope.status = ' ';
$scope.showAdvanced = function(ev,_url) {
$mdDialog.show({
controller: DialogController,
templateUrl: _url,
parent: angular.element(document.body),
targetEvent: ev,
clickOutsideToClose:true
}).then(function(answer) {
$scope.status = 'You said the information was "' + answer + '".';
}, function() {
$scope.status = 'You cancelled the dialog.';
});
};
});
function DialogController($scope, $mdDialog) {
$scope.hide = function() {
$mdDialog.hide();
};
$scope.cancel = function() {
$mdDialog.cancel();
};
$scope.answer = function(answer) {
$mdDialog.hide(answer);
};
}
And in my HTML page I have this:
<a ng-click="openDetailDialog()">Show details</a>
<script type="text/javascript">
function openDetailDialog(id) {
var id = getValue(id, 'id');
showAdvanced($event,'${readDetailURL}&id=' + id + '/');
}
</script>
The problem is that when I add the function showAdvanced() inside another function, it doesn't work.
When I call this function directly in ng-click, it works.
This works:
<a ng-click="showAdvanced($event,'http:myurl/test/id');">Show details</a>
Why?

First you can't attach or bind something that is not on the $scope, or the controller itself.
<a ng-click="openDetailDialog()">Show details</a>
That's wrong.
And second you can't access variables attached to the scope from plain javascript, 2WDB (two way data binding) just include HTML. And of course angular works with encapsulated scope.

The function ´showAdvanced()actually is part of the$scope`element. When you do this in your html:
<a ng-click="showAdvanced()">text</a>
AngularJs changes that (behind the scenes) to $scope.showAdvanced()
If you want to call it from javascript, you could try and change your function call to
`$scope.showAdvanced()`

Related

Not able to obtain value in view (directive)

I have an array in the profile-form.html directive's controller.
But I am neither able to obtain the value of that array (all_languages) nor iterate over it using ng-options in the directive. It's simply printing as string. I am new to Angular and maybe doing everything terribly wrong.
Directive
app.directive("profileForm", function() {
return {
restrict: "E",
templateUrl: "/static/translatorNgApp/profile-form.html",
controller: ['$scope','$http',function($scope, $http) {
this.getCookie = function(name) {
var cookieValue = null;
if (document.cookie && document.cookie != '') {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var cookie = jQuery.trim(cookies[i]);
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) == (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
console.log(cookieValue);
return cookieValue;
};
$scope.csrftoken = this.getCookie('csrftoken');
$scope.myForm={};
$scope.all_languages = ['English', 'Hindi'];
$scope.language_pairs = [];
$scope.getAllLanguages = function () {
$http.get('/getAllLanguages'
).success(function(response) {
// success
$scope.all_languages.concat(response);
}).error(function(response) {
// failed
});
};
$scope.submitForm = function() {
var postData = {
method: 'POST',
url: '/accounts/tprofile/',
// headers : {'Content-Type':'application/x-www-form-urlencoded; charset=UTF-8'},
headers: {'X-CSRF-Token' : $scope.csrftoken },
data: $scope.myForm
};
$http(postData)
.then(function(response) {
// success
},
function(response) { // optional
// failed
});
console.log("Form submitted");
// $scope.message = "Sent Successfully 2";
// console.log(postData);
console.log(postData);
console.log($scope.myForm);
};
$document.ready(function(){
console.log("document ready");
$scope.getAllLanguages(); //This can be commented out for the question's sake.
});
}],
controllerAs: "profileFormCtrl"
};
});
Directive Template (profile-form.html)
<div class="form-group" >
<label for="id_source_language">Source language: </label>
<ul>
<li>
<pre>all_languages = {{all_languages | json}}</pre>
<select data-ng-model="source" ng-options="language for language in all_languages" class="form-control" id="id_source_language" name="source_language" placeholder="Source Language" required>
</select>
<button ng-click="language_pairs.pop($index)" aria-label="Remove">Remove</button>
<button ng-click="language_pairs.push({})">Add more pair</button>
</li>
</ul>
</div>
Using document.ready event inside a angular directive doesn't make sense to call specific method of scope. Because document.ready event has already happened after that event only angular started process page.
Ideally to make your code working state you need to remove $document.ready(function(){ .... }); code which isn't required there. And as document.ready is already accomplished, so the one which you had registered from directive wouldn't get call.

pass parameter from one controller to another page controller

.controller('ExplorerCtrl', ["$scope", "appServices","$location", 'appSettings', function ($scope, appServices, $location, appSettings) {
$scope.changeLocation = function() {
$location.path('career'?name={{career.Name}});
};
$scope.getCareerList = function(){
appServices.doAPIRequest(appSettings.appAPI.career.overviewList, null, null).then(function(data){
$scope.allCareer = data.data.n;
})
};
How to pass parameter from one controller to another page controller. the career.name I want to b appended in my next page API.

How to pass value from ng-click (AngularJS) to Laravel?

How to get value from ng-click and send to laravel for query?
//.html
<div ng-controller="recipientsController">
<div ng-repeat="recipient in recipients | orderBy:'-created_at'" ng-click="select(recipient.id)">
<p class="recipientname">{{ recipient.name }}</p>
</div>
</div>
//xxController.js
$scope.select = function() {
Comment.get()
.success(function(data) {
$scope.comments = data;
$scope.loading = false;
});
}
//xxService.js
get:function(){
var comments = $http.get('api/comments');
return comments;
},
//xxController.php [laravel]
public function index()
{
$comments = DB::table('c')
->join('u', 'c.id', '=', 'u.id')
->select('u.id', 'u.name', 'c.comments', 'c.created_at')
->where('u.id','=', Auth::user()->id)
->orWhere('u.id','=', **39 => this part has to be from ng-click value**)
->orderBy('c.created_at','asc')
->get();
return Response::json($comments);
}
You have passing the recipient.id parameter in your ng-click function but you did't retrieve the parameter in your js function
you need to retrieve the parameter
$scope.select = function(**id**) {
var selectedId=id;//you can check here
Comment.get()
.success(function(data) {
$scope.comments = data;
$scope.loading = false;
});
}
For passing data with $http.get method, there is second argument for [config] you can use that.
see: https://docs.angularjs.org/api/ng/service/$http#get for more reference about get method

Passing data from Service AngularJS

Dear all I am having trouble with the scope of my $scope or how should I put it.
I am retrieving the data from my Service successfully but I´m having trouble with accessing $scope.players and $scope.tournament and I think it has something to do with being inside the service call. If I console.out() inside the service call everything is just fine. How can I be able access the data which is inside of the service call.
Version 1:
Here console log simply states undefined.
.controller('SelectCtrl', ['$scope','$stateParams', '$location', '$window','playerService','tournamentService', function ($scope, $stateParams, $location, $window, playerService, tournamentService) {
init();
function init() {
playerService.getPlayers().then(function (data) {
$scope.players = [];
angular.forEach(data, function (player, index) {
$scope.players.push(player.info);
});
});
tournamentService.getTournaments().then(function (data) {
var result = data.filter(function (element) {
if (element.ID == $stateParams.id) {
return true;
} else {
return false;
}
});
$scope.tournament = result;
});
};
console.log($scope.tournament);//undefined
console.log($scope.players); //undefined
}
Version 2:,
Here console log simply states the Object {then: function, catch: function, finally: function} Which is not what I wan´t I want the data to be able to display it in my view.
.controller('SelectCtrl', ['$scope','$stateParams', '$location', '$window','playerService','tournamentService', function ($scope, $stateParams, $location, $window, playerService, tournamentService) {
init();
function init() {
$scope.players = playerService.getPlayers().then(function (data) {
$scope.players = [];
angular.forEach(data, function (player, index) {
$scope.players.push(player.info);
});
});
$scope.tournament = tournamentService.getTournaments().then(function (data) {
var result = data.filter(function (element) {
if (element.ID == $stateParams.id) {
return true;
} else {
return false;
}
});
$scope.tournament = result;
});
};
console.log($scope.tournament);//Object {then: function, catch: function, finally: function}
console.log($scope.players);//Object {then: function, catch: function, finally: function}
}
Your help is really appreciated!
The Services:
.factory('playerService', function ($http,$q) {
return {
getPlayers: function () {
//return the promise directly.
var deferred = $q.defer();
$http.get(webServiceUrl + 'api/Player/GetAllPlayers')
.success(function (data) {
//resolve the promise as the data
deferred.resolve(data);
}).error(function () {
deferred.reject();
});
return deferred.promise;
}
}
})
.factory('tournamentService', function ($http,$q) {
return {
getTournaments: function () {
//return the promise directly.
var deferred = $q.defer();
$http.get(webServiceUrl + 'api/Tournament/GetAllTournaments')
.success(function (data) {
//resolve the promise as the data
deferred.resolve(data);
}).error(function () {
deferred.reject();
});
return deferred.promise;
}
}
})
Part of the view:
<h1 style="display: inline-block; margin-left:15px;">Enter <i>{{tournament.Name}}</i></h1>
<div class="row">
<div class="selectinforow">
<div class="col-xs-2 selectinfo">
<span>{{tournament.EntryFee}}$</span></br>
<span>Entry Fee</span>
</div>
<div class="col-xs-2 selectinfo">
<span>{{tournament.Entries}}</span></br>
<span>Entries</span>
</div>
<div class="col-xs-2 selectinfo">
<span>{{tournament.Size}}</span></br>
<span>Max Size</span>
</div>
<div class="col-xs-2 selectinfo">
<span>{{tournament.StartTime}}</span></br>
<span>Start Date</span>
</div>
<div class="col-xs-2 selectinfo">
<span>{{tournament.Entryfee*tournament.Entries}}$</span></br>
<span>Winnings</span>
</div>
</div>
</div>
So if you read your code carefully you will notice you are using a promise on the following line:
tournamentService.getTournaments().then(function (data) {
// [your data is set here - AFTER the service call runs]
}
// [your print is here - run BEFORE service call runs]
The key to the "then" statement is it isn't executed right away, but is instead run when data is returned from the service call. In other words, you have your print in the wrong spot - I would expect the values to be undefined there. If you move the console.log statements into the promise (then) - I would expect to see the valid values. You can also put a break point in the browser debugger to see the values in the "then" function if you want to validate that things are working. Hope this puts you on the right track!
EDIT
Once the promise completes, angular automatically updates the view. Lets say you have the following in your view (just an example):
<h1 ng-bind="tournament.Title">Default Text</h1>
When the view/page loads you will see "Default Text". After the promise completes, if a tournament has been loaded, angular will automatically update the "h1" to now have the Title for that tournament. This happens because angular automatically runs an "$apply()" after a promise completes.
Your code is executed before the promise response.
If you need to code "procedurally", you should $watch the scope variable as below to detect any changes.
For example:
$scope.$watch('tournament', function() {
console.log($scope.tournament);
}, true);

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