angular does not load my directive - angularjs

I newly start to use angular.but I have some problem to loading my directive.
I want to load my directive as soon as page loaded.
where I load data-show directive
<div class="row">
<div class="col-md-12">
<article class="row" ng-controller="DataCtrl">
<input type="button" ng-click="getDataList()" >
<h1>Some Content Here</h1>
<ul id="home" bread-crumbs></ul>
<ul class="thumbnails">
<li ng-repeat="data in list" class="col-md-5">
<show-data data="data"/>
</li>
</ul>
</article>
</div>
</div>
showData directive:
app.directive('showData', function () {
return{
restrict: 'E',
replace:true,
templateUrl: 'views/directives/datas.directive.html',
scope: {
data: "="
},
controller:'DataCtrl'
}
})
and template I used in:
<div class="well hoverwell">
<div class="row">
<h2 class="col-md-4">{{data.name}}</h2>
</div>
<div class="row">
<span class="col-md-1">Code:</span>
<span class="col-md-1">{{data.id}}</span>
</div>
<div class="row">
<span class="col-md-1">accountability:</span>
<span class="col-md-1">{{data.parent}}</span>
</div>
<div class="row">
<span class="col-md-1"> :</span>
<span class="col-md-1">{{data.definition}}</span>
</div>
</div>
and my controller
'use strict';
angular.module('app')
.controller('DataCtrl', function ($scope, DataService, $log) {
$scope.getDataList = function () {
var list = DataService.getDataList(1);
list.then(
function (result) {
$log.info(result);
$scope.dataList = result;
}, function (status) {
$log.error(status)
$scope.msg = "error " + status + " has been occur,please report to admin ";
});
};
});
and when I run my app it does not work .
when I watch it in chorome development tools my directive is comment
what is my problem.How can I call this directive as soon as page load.
thx

As you already noticed, you see empty list because your dataList in ng-repeat is not filled yet.
But you have some errors in your code:
First of all - you should never use one controller twice. So you need to create separate controller for your directive.
replace directive parameter is deprecated, better not to use it.
In your DataCtrl you set the dataList variable: $scope.dataList = result;, but in HTML you refer to list variable: <li ng-repeat="data in list" class="col-md-5">.
Maybe that example will help you to figure out with your code.

Related

Update view when api get data in Angularjs

So, i have a little problem. I made a tiny webapp that uses the omdb api. The thing is this that when i type in the movie that i'm searching for then press the search button, the view should change to the result.html view and show the data i got from the api.
The api works fine. I got the data to display, but that was in my index.html. Now i have splitted the files by using ng-routes
I can provide you the whole project if you wanna look at it. Maybe i can upload it to a online editor somewhere?
This is my app.js
var myApp = angular.module("myApp", ['ngRoute']);
myApp.config(['$routeProvider', function ($routeProvider) {
$routeProvider.
when('/home', {
templateUrl: 'views/home.html',
controller: 'filmController'
}).
when('/result', {
templateUrl: 'views/result.html',
controller: 'filmController'
}).otherwise({
redirectTo: '/home'
})
}]);
myApp.controller("filmController", function filmController($scope, $http, $window) {
$scope.getData = function () {
var movieTitle = document.getElementById("filmName").value;
var binding = document.getElementsByClassName("ng-binding");
$http
.get("http://www.omdbapi.com/?t=" + movieTitle + "&apikey=526345a6")
.then(function (response) {
var data = response.data;
if (data.Error) {
alert("Film inte funnen");
return false;
}
for (let key in data) {
if (data.hasOwnProperty(key)) {
let element = data[key];
if (element === "N/A") {
data[key] = "Inget hittat";
if (key === "Poster") {
$scope.post = "Ingen poster hittad";
}
}
$scope.url = data;
}
}
if (data.Ratings.length === 0) {
$scope.rate = "Ingen utmärkelse/er hittad";
}
// This api data is printed to the console on the index.html view, i want it in the result view...
console.log(data);
});
};
});
This is my index.html
<body>
<div class="main-content">
<!-- <div class="container">
<div class="row">
<div ng-controller="MyController">
<div ng-repeat="item in larare" class="col-lg-12">
<div class="card">
<img ng-src="/images/{{item.shortname}}.jpg" alt="Bild på {{item.name}}" class="card-img-top">
<div class="card-body">
<h3 class="card-title">{{item.name}}</h3>
<p class="card-text">{{item.reknown}}</p>
</div>
</div>
</div>
</div>
</div>
</div>
</div> -->
<header ng-include="'header.html'"></header>
<main ng-view></main>
</div>
</div>
<script>
var elem = document.getElementsByTagName("body")[0];
if (elem.requestFullscreen) {
elem.requestFullscreen();
console.log("Nu");
} else {
console.log("Error");
}
function updateSite(event) {
window.applicationCache.swapCache();
}
window.applicationCache.addEventListener('updateready',
updateSite, false);
</script>
<script src="./js/formvalidation.js"></script>
</body>
</htm>
And my result view
<div class="show container" ng-show="url.Title">
<div class="poster">
<!-- <img ng-src="{{ url.Poster }}" alt="" /> -->
<img ng-src="{{ url.Poster == 'Inget hittat' ? './images/image_not_found.png' : url.Poster }}">
<p class="text-dark">{{ post }}</p>
</div>
<h2 class="text-dark">{{ url.Title | uppercase}}</h2>
<div class="movie-info">
<p class="text-dark">
<strong>Från:</strong> {{ url.Year }}</p>
<p class="text-dark">
<strong>Rating:</strong> {{ url.Rated }}</p>
<p class="text-dark">
<strong>Utgiven:</strong> {{ url.Released }}</p>
<p class="text-dark">
<strong>Längd:</strong> {{ url.Runtime }}</p>
</div>
<p class="text-dark">
<strong>Skådespelare:</strong> {{ url.Actors }}</p>
<p class="text-dark">
<strong>Regissör:</strong> {{ url.Director }}</p>
<p class="text-dark">
<strong>Utmärkelser:</strong> {{ url.Awards }}</p>
<p class="text-dark">
<strong>Handling: </strong> {{ url.Plot }}</p>
<h4 class="text-dark">
<strong>Utmärkelser</strong>
</h4>
<p class="text-dark ">{{ rate }}</p>
<div ng-repeat="rating in url.Ratings | orderBy: '-Value'">
<p class="text-dark">
<strong>{{ rating.Source + ': ' + rating.Value }}</strong>
</p>
</div>
This is my home view
<section class="text-white">
<img src="./images/background.jpg" alt="Bild på poster från Frankenstein filmen" class="bg-image">
<div class="main container align-middle">
<div class="row text-center justify-content-center section-intro">
<div class="col-6 mb-5">
<h1>Filmtipset</h1>
<h5>Sök efter dina favortfilmer</h5>
</div>
</div>
<form ng-submit="getData()">
<div class="inputSearch mx-auto">
<div class="row justify-content-center">
<div class="col-8">
<div class="form-group">
<label for="filmName">Film</label>
<input class="form-control" type="text" name="filmName" id="filmName" placeholder="Ex. Armageddon" autofocus>
</div>
<input type="submit" class="btn btn-primary btn-lg btn-block btn-info mt-5" onclick="validateForm()" ng-click="'#!/result'">
</div>
</div>
</form>
Just a few notes before we break down the issue you are seeing. It seems like you aren't using angularjs to its full potential. Using a mixture of jquery and angularjs is not best practice and can make debugging very difficult. I would recommend making movieTitle an ng-model, as well as using angularjs's built in form validation. This will allow you to access the movieTitle easily in your controller as well as take advantage of angular's built in form controller and actions.
As for getting the data to your other page, I would add a second controller for that page, then from your filmController, you can pass the movie title as a route param when changing views. In your resultController, you can get the movie title from the route param and then do your api call while initializing the result page/controller.
In your home.html file, we will add ng-model to the input to be more angularjs friendly. Now we can access movieTitle in the controller with $scope.movieTitle. I am also changing the method that should get run on submit to the search() method I have added to the filmController.
home.html
<form ng-submit="search()">
// ... your other html here
<input class="form-control" type="text" name="filmName" id="filmName" ng-model="movieTitle" placeholder="Ex. Armageddon" autofocus>
In your filmController, I would add $location and move the getData() method to a resultController. We will now call search() on form submit, then use $location to switch views to your result view, attaching the movie title as a route param so we can access it in the resultController.
filmController.js
myApp.controller("filmController", function filmController($scope, $http, $location) {
// ... other code you have
// this will be what gets called after the user types a movie title
$scope.search = function () {
var title = $scope.movieTitle; // or using jquery(not recommended)
// this will change location and will produce
// the url: http://[yoursite]/result?movieTitle=title
$location.path('/result').search({movieTitle: title});
}
});
In your newly created resultController, we will get that route param and use it to search for the data.
resultController.js
myApp.controller("resultController", function resultController($scope, $http, $routeParams) {
// the getData method moved to this controller
$scope.getData = function (movieTitle) {
$http
.get("http://www.omdbapi.com/?t=" + movieTitle + "&apikey=526345a6")
// the rest of your code for getData here
};
// I like to make an init method to make it clear what we are initializing
$scope.init = function () {
// this will get the movieTitle from the /result?movieTitle=title part of your url
var movieTitle = $routeParams['movieTitle'];
// now we call the method you have that uses the omdb api
// just modify it to accept the movie title as a param rather than finding it in the html
$scope.getData(movieTitle);
}
// run init method
$scope.init();
});
Finally, you will want to update your app config to have your result route use the resultController we added instead of the filmController.

Angularjs passing id into modal function()

I am using angularjs and spring mvc for my application. At first I am displaying all the placements with one button Placed Candidates. I am doing ng-repeat for displaying all the placements.
Here is my html.
<div class="row" data-ng-repeat="placement in placements">
<div class="col-xs-12 col-sm-12 col-md-12">
<h5>{{placement.companyName}}</h5>
</div>
<div class="col-xs-12 col-sm-6 col-md-3">
<h6>{{placement.placementDate | date:'dd MMM yyyy'}}</h6>
Company Target (appox):10 Achieved:
</div>
<a href="javascript:void(0);" data-ng-
click="placedcandidatespopup(placement.placementId);">//here i can
get particular placementId but how to pass this id to
savePlacementStudents() method in controller.js???//
PlacedCandidates
</a>
</div>
I am calling one modal popup function. Here is controller.js
$scope.placedcandidatespopup = function()
{
AdminUsersService.getAllUsers().then(function(response)
{
$scope.allusers=response.data;
console.log($scope.allusers);
})
$(".placedcandidates").modal("show");
}
I am calling modal by name "placedcandidates".
Here is the modal
<div class="modal right fade placedcandidates" id="myModal1"
tabindex="-1" role="dialog" aria-labelledby="myModalLabel2">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-body">
<div class="row">
<div class="col-xs-12 col-sm-6 col-md-6" data-ng-
repeat="student in allusers">
<input id="{{student.studentId}}" type="checkbox" value="
{{student.studentId}}" data-ng-
checked="selection.indexOf(student.studentId) >-1"
data-ng-click="toggleSelection(student.studentId)"/>
<label for="{{student.studentId}}"></label>
{{student.firstName}}
</div>
</div>
</div>
<div class="modal-footer" style="position: fixed;">
<input type="button" value="Submit" class="btn" data-ng-
click="savePlacementStudents()">
</div>
</div>
</div>
</div>
After clicking on button popup modal will display with all Students with checkboxes placed beside them.Now I am able to save studentId into database.But I am not able to pass placementId for saving.
Here is my savePlacementStudents method in controller.js.
$scope.selectedStudents = {};
$scope.savePlacementStudents = function(selectedStudents)
{
selectedStudents.selectedList = $scope.selection;
AdminPlacementService.savePlacementStudents(selectedStudents).then
(function(response)
{
if(response.data=="success"){
$window.scrollTo(0,0);
$scope.selectedStudents = {};
$scope.getplacementdetails($scope.currentPageIndex);
$scope.successmessage="Student Selection Saved!;
$timeout(function() {
$scope.successmessage="";
$scope.closeplacedcandidatespopup();
}, 1500);
}
});
}
Can anyone tell how can I pass respective placementId to this saveStudents method() so that I can set that placementId for those students selected.
Here is the solution.
The placementId passed to function placedcandidatespopup can be saved as follows in function placedcandidatespopup
$scope.selectedPlacementId = placementId;
Now the same $scope will have access in Popup also as it is using same controller.js. And now you can use this $scope.selectedPlacementId anywhere in controller.js
So you don't need to pass placementId...!!
Hope that would help you..!!
$scope.placedcandidatespopup = function(id)
{
AdminUsersService.getAllUsers().then(function(response)
{
$scope.allusers=response.data;
console.log($scope.allusers);
})
$scope.inserted = {
placementId:id,
};
var modalInstance = $uibModal.open({
templateUrl: 'views/test/myModal1.html',
controller: 'TestCntrl',
size: "Modelwidth",
resolve: {
items: function () {
return $scope.inserted;
}
}
});
}
In model you have to access using items.placementId and when you savePlacementStudents() method send placementId as well with student info.

How to get param from one controller to another?

My question is best explained when I straight go to the code.
HTML part:
<div class="panel panel-default post" ng-repeat="post in posts">
<div class="panel-body">
<div class="row">
<div class="col-sm-2">
<a class="post-avatar thumbnail" href="/profile#/{[ post.profileID ]}">
<div class="text-center">{[ user.fullname ]}</div>
</a>
</div>
</div>
</div>
When I click on the /profile#/{[ post.profileID ]} link - it takes me to the profile page. All good here.
However, I am using ngView so I have separated it like this:
<div class="col-md-3">
<div>Some HTML stuff</div>
</div>
<div class="col-md-6">
<div ng-view></div>
</div>
<div class="col-md-3">
<div>Some HTML stuff</div>
</div>
My ngView makes use of the /profile#/{[ post.profileID ]} param and I use it to display whatever I have to display.
The problem:
I can get the profileID param in my angular controller but once I get it, how will I be able to pass it onto other controllers?
My controller looks like the below:
var profileApp = angular.module('profileApp', ['ngRoute']);
profileApp.config(function($routeProvider) {
$routeProvider
.when('/:id', {
templateUrl : 'partial/profile/feed.html',
controller : 'mainController'
})
.when('/posts:id', {
templateUrl : 'partial/profile/posts.html',
controller : 'postsController'
});
});
profileApp.controller('mainController', ['$scope', '$http', '$routeParams', function($scope, $routeParams){
console.log($routeParams.id);
}]);
profileApp.controller('postsController', ['$scope', '$routeParams', function($scope, $routeParams){
console.log($routeParams.id);
}]);
As you can see, I get get the param passed from the HTML link and use it in the mainController but how will I get the param to be a link in the col-md-3 (just like the original /profile#/{[ post.profileID ]})?
Hope this makes sense. It's has been driving me nuts!
Thanks
Why don't you just edit your partial HTML pages and put the columns in it.
For partial/profile/feed.html :
<div>
<div class="col-md-6">
<div>feed stuff</div>
</div>
<div class="col-md-3">
</div>
</div>
And partial/profile/posts.html could be :
<div>
<div class="col-md-6">
</div>
<div class="col-md-3">
<div>posts stuff</div>
</div>
</div>
So I did some research into this and I just ended up using services.
See below for the answer:
profileApp.service('globalParams', function() {
var profileID = '';
return {
getProfileID: function() {
return profileID;
},
setProfileID: function(value) {
profileID = value;
}
};
});
You then pass the service into the dependencies in the controllers, like below:
profileApp.controller('mainController', ['$scope', 'globalParams', function($scope, globalParams){
//some code
};
And you can call the functions for getting and setting the variables.

AngularJS: Access models using dynamic names in template

I have a template with a lot of what is essentially duplicate code. I'd like to use a directive to include a partial template which I can manipulate for each "block" of duplicate code.
The template currently looks something like this:
<div class="column book">
<div class="header">
<input type="text" id="book_query" ng-model="book_query.name" />
</div>
<div class="content">
<div class="row" ng-repeat="book in books | filter:book_query">
{{book.name}}
</div>
</div>
</div>
....
<div class="column game">
<div class="header">
<input type="text" id="game_query" ng-model="game_query.name" />
</div>
<div class="content">
<div class="row" ng-repeat="game in games | filter:game_query">
{{game.name}}
</div>
</div>
</div>
....
And the controller just gets the data and adds it to the scope e.g.
$scope.books = data.books;
$scope.games = data.games;
What I started doing was using a directive which takes in an argument (e.g. book, game etc) so I then knew which model(s) to use. The problem I have is how to use the argument to access the model in the template? The directive itself is, currently, very simple:
<div item-column item="book"></div>
<div item-column item="game"></div>
app.directive('itemColumn', function() {
return {
scope: {
item: '#'
},
replace: true,
templateUrl: 'item_column.html'
};
});
In item_column.html, I was hoping I could just substitute the item argument, which works fine for displaying the value of the arg but not for replacing where 'book' or 'game' is used for the models e.g.
<div class="column {{item}}">
<div class="header">
<input type="text" id="{{item}}_query" ng-model="{{item}}_query.name" />
</div>
<div class="content">
<div class="row" ng-repeat="item in ??? | filter:{{item}}_query">
{{item.name}}
</div>
</div>
</div>
Can someone show me the best way of doing this? I don't doubt I'm going the complete wrong way about it!
EDIT: The original issue above is now pretty much fully solved using JoseM's answer below. The one outstanding issue is the on-click functions on each element no longer firing the parent scope from within the isolated scope.
My controller is laid out like so:
app.controller('ItemsCtrl', ['$scope', '$http', 'CONFIG', function($scope, $http, CONFIG) {
var items = ['books', 'games'];
items.forEach(function(item) {
$scope[item] = [];
$scope['selected_'+item] = null;
})
$scope.getItem = function(item) {
$http.get('?action=get_item&id='+item.id+'&type='+item.type)
.success(function(data) {
// update model
})
.error(function(data, status) {
// do something
});
}
}]);
$scope.getItem is no longer accessible when clicking on the item in the view, which looks similar to the following after implementing JoseM's answer:
<div class="row" ng-repeat="item in array | filter:query">
<div class="text" ng-click="getItem(item)">
{{item.name}}
</div>
</div>
Is there a simple way of making the parent scope functions available from within the isolated scope? Or is there a better place for these functions? Apologies for (what I feel are) the very basic questions - I'm still trying to get my head around Angular!
One way to accomplish what you want is by using a child scope in your directive and then doing your own "linking" of the parent scope variables using a watch on the parent scope value.
in your directive:
app.directive('itemColumn', function() {
return {
scope: true,
templateUrl: 'item_column.html',
link: function(scope,elem,attrs) {
var varName = scope.varName = attrs.item;
var parScope = scope.$parent;
parScope.$watch(varName + 's', function(newVal){
scope.theArray = newVal;
});
parScope.$watch(varName + '_query', function(newVal){
scope.theQuery = newVal;
});
}
};
});
in your template:
<div class="column {{varName}}">
<div class="header">
<input type="text" ng-attr-id="{{varName}}_query" ng-model="theQuery.name" />
</div>
<div class="content">
<div class="row" ng-repeat="item in theArray | filter:theQuery">
{{item.name}}
</div>
</div>
</div>
If you want to use an isolated scope, you could it, but then you would have to supply at least 3 attributes if you are using the same properties as above. I personally believe that using an isolated scope is a better way of doing it. See below how the isolated version is simpler:
isolated version of directive
app.directive('itemColumn2', function() {
return {
scope: {
label: '#',
array: '=',
query: '='
},
templateUrl: 'item_column2.html'
};
});
isolated version of template
<div class="column {{label}}">
<div class="header">
<input type="text" ng-attr-id="{{label}}_query" ng-model="query.name" />
</div>
<div class="content">
<div class="row" ng-repeat="item in array | filter:query">
{{item.name}}
</div>
</div>
</div>
usage
<div item-column2 label="book" array="books" query="book_query"></div>
<div item-column2 label="game" array="games" query="game_query"></div>
And finally here is a sample plunker: http://plnkr.co/edit/OyEHR4ZhzYKvs4jeDfjD?p=preview

How do I target just one instance of a nested repeat?

This is probably pretty basic, but I'm going round in circles.
I have a nested controller in a ng-repeat - I would like to trigger an event in an instance of the repeat that will affect only the nested controller in that instance, not the nested controller in all instances.
Here is a basic example to try and make things clearer:
<div ng-controller="PostsCtrl">
<div ng-repeat="post in posts">
<p>{{post.body}}</p>
<div ng-controller="CommentsCtrl">
<div ng-repeat="comment in comments">
<p>{{comments.body}}</p>
<a href ng-click="showComments(post.id)">Show comments</a>
</div
</div>
</div>
</div>
angular.module('myApp')
.controller('PostsCtrl', function ($scope, Restangular) {
var posts = Restangular.all('posts');
posts.getList().then(function(posts) {
$scope.posts = posts;
});
$scope.showComments = function(id) {
$scope.$broadcast('SHOW_COMMENTS', id);
};
});
angular.module('myApp')
.controller('CommentsCtrl', function ($scope, Restangular) {
$scope.$on('SHOW_COMMENTS', function(event, id) {
var post = Restangular.one('posts', id);
post.get().then(function(post) {
$scope.comments = post.comments;
});
});
});
What would happen in this example is that all instances of the comments controller would be populated with the same comments - I just need to be able to target the relevant one. I'm sure I'm missing something pretty fundamental, and probably going about this the wrong way.
Many thanks.
You're broadcasting "SHOW_COMMENTS" to all repeated posts. You need to isolate the scope per Post.
Isolate the scope using ng-controller="PostCtrl".
<div ng-controller="PostsCtrl">
<div ng-repeat="post in posts" ng-controller="PostCtrl">
<p>{{post.body}}</p>
<div ng-controller="CommentsCtrl">
<div ng-repeat="comment in comments">
<p>{{comments.body}}</p>
<a href ng-click="showComments()">Show comments</a>
</div
</div>
</div>
</div>
Move show comments from PostsCtrl to PostCtrl.
angular.module('myApp')
.controller('PostCtrl', function ($scope) {
$scope.showComments = function() {
$scope.$broadcast('SHOW_COMMENTS', $scope.post.id);
};
});
Do you really need to use events? You could use ng-if instead.
Your comments are embedded in each Post anyway so why request them again. In this case you could do like something this...
<div ng-controller="PostsCtrl">
<div ng-repeat="post in posts" ng-controller="PostCtrl">
<p>{{post.body}}</p>
<a href ng-click="toggleComments()">Show comments</a>
<div ng-controller="CommentsCtrl" ng-if="showComments">
<div ng-repeat="comment in post.comments">
<p>{{comments.body}}</p>
</div
</div>
</div>
</div>
Toggle comments...
angular.module('myApp')
.controller('PostCtrl', function ($scope) {
$scope.showComments = false;
$scope.toggleComments = function() {
$scope.showComments = !$scope.showComments;
};
});

Resources