Hi i have the following plunker using a factory: plunker
When we click the button next to my academic programs, it gives a panel with the applied science and academic buttons. When we click on one of the buttons, it gives a list of some programs. When we click on one of those programs, it brings another panel which should contain the children of those programs.
I defined these children in a factory(services.js). But it is not bringing those elements from the json file. Where am i going wrong?
your path to your data.json (its currently data.js) file is wrong.
the json in the file is incorrect. You need to wrap all properies with ''.
Your path to bootstrap is wrong so its crashing on $().tooltip()
You had not even plugged up the service call. I added jsonService as a dependancy. JsonService as an injectable:
var app = angular.module('StudentProgram', ['ui.bootstrap', 'jsonService']);
app.controller('mycontroller', function(JsonService, $scope, $modal, $log) {
Then i added to your scope a call to get the data
JsonService.query(function(data){
$scope.degreecategories = data;
console.log(data);
});
Working plnkr . Please next time point more work into your question... you are lucky I am bored.
Related
For quick reading, the problem is simplified under "The problem", and for further information keep going down for background and notes before answering. Thank you!
The problem
I want to delete the instance of a controller when refreshing the page or when moving to a different view and then returning to the same view through the navigator (nav.html). In fact, every time view X.html is visited, I want the program to check if X-controller.js exists, and if it does delete it before making a new instance.
How far am I going here, is it a 2 line solution I failed to find online or am I looking at hours of coding to make this work?
Background
My project uses the $routeProvider service, not the the ng-controller directive. Once the app launches there are constantly two views, one on the top where you can navigate back and forth through the controllers "Home - Contact - Support" (logically, nav.html), and one on the bottom which is the "Home" or "Contact" and so on.
I haven't had any problems with this arrangement until the code begun making massive calculations. The same instance of the controller is updated with more data than it should, calculates for previous data that was discarded, and so on. I've read online about deleting the controller but as far as I know it's not that easy.
Notes before answering the question:
If the second option of 'hours of coding' is the solution I'm not expecting anyone to do this for me, but references to articles or code for that would be appreciated because I haven't found anything useful on my own.
If there is an easier solution that applies only when ng-controller is used and not $routeProvider then it's not an option for me. There are over 20 views and many sections of code which triggers redirection to a different view with a different controller using event listeners. I'm not currently planning on changing $routeProvider to ng-controller.
If the solution doesn't actually delete the previous instance, rather clears the $scope and javascript variables then that could work for me as well.
I haven't included code because this question is not about a bug or error, if for some reason code snippets of the $routeProvider configuration or one view and controller is needed let me know and I'll include that code with the classified sections replaced with similar dummy code.
Clarification Edit
I'll illustrate with an example. Assume X.html is a view controlled by XCtrl.js. $scope.test is initiated in the beginning $scope.test = 2 of that controller, and once a button in the view is clicked $scope.test becomes 3. Also, the X view displays $scope.test all the time. So I moved to that view, clicked the button, and saw that 3 is displayed on the screen. Then I moved to "Home" through the navigator, then back to "X", and 3 is still displayed. But what I want is 2 to be displayed, and not 3. I want everything to be renewed in that controller.
Solution
Eventually I used a different technique to solve this. All the data saved in the local storage was affecting the $scope variables (there were too many variables to track that I didn't notice this). To solve the issue I cleared the local storage key localStorageService.set('keyUsed', []); once the view controlled by controller X is visited. Assume an init function, so the line of code clearing the local storage was placed in the top of that function.
I'm still marking the correct solution from the answers below for the problem I initially thought I had.
Always have a '.' in your ng-models!
-- Miško Hevery (father of AngularJS)
Most likely you have an issue with $scope.test and not with controller itself. If your template x.html refers the value of test as {{test}} (without any prefix) then most probably you are referring the test of the wrong scope. It usually happens due to prototypical chain of scopes that extend one another and fallback to prototype property value. In this case, choose something unique for XCtrl controller and put all your state inside this controller to that namespace. For example, use x as namespace
$scope.x = {};
$scope.x.test = 2;
instead of just
$scope.test = 2;
Then in x.html refer the value as
{{x.test}}
This is one of the Angular best practices.
Another best practice, that may solve your issue, is actually not using $scope at all, but use controller instance itself for storing state in junction with controllerAs syntax:
index.html
<!DOCTYPE html>
<html ng-app="app">
<head>
<script data-require="angular.min.js#1.5.8" data-semver="1.5.8" src="https://code.angularjs.org/1.5.8/angular.min.js"></script>
<script data-require="angular-route.min.js#1.5.8" data-semver="1.5.8" src="https://code.angularjs.org/1.5.8/angular-route.min.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body ng-view>
</body>
</html>
script.js
angular.module('app', ['ngRoute'])
.config(['$routeProvider', function($routeProvider) {
$routeProvider
.when('/x', {
controller: 'xCtrl',
controllerAs: 'x',
templateUrl: 'x.html'
})
.when('/y', {
controller: 'yCtrl',
controllerAs: 'y',
templateUrl: 'y.html'
})
.otherwise({
redirectTo: '/x'
})
}])
.controller('xCtrl', [function() {
var x = this;
x.test = 2;
x.doSomething = function() {
x.test ++;
};
}])
.controller('yCtrl', [function() {
var y = this;
y.hello = 'Hello';
}])
x.html
<h1>X.html</h1>
<p>test = {{x.test}}</p>
<button ng-click="x.doSomething()">+1</button>
Link to Y
y.html
<h1>Y.html</h1>
<p>{{y.hello}}</p>
Link to X
Live Demo:
https://plnkr.co/edit/EpUn94uWMliTaG5mvPxv?p=preview
Links:
To understand the issue with not having a '.' in your model, see this video by Miško Hevery.
To better understand controllerAs approach, you can read this post by Todd Motto.
I started my project using the Ionic Side Menu Starter.
I'm trying to get a Rating directive/control to work, from here:
https://github.com/fraserxu/ionic-rating
The module is loaded, and the template objects (the stars) render OK. Binding -from- my model/scope works one-time. But, clicking on the stars does nothing.
Some of the js does get invoked: ng-mouseleave="reset()" is hooked up to the parent element and does get invoked. But ng-click="rate($index + 1)" is attached to the that contains the star, and does not (I set breakpoints).
I suspect it may have something to do with the child scopes that are created based on the starter, but don't know.
<rating ng-model="review.rating" max="5"></rating>
And my controller:
angular.module('myapp.controllers').controller('NewReviewCtrl', function($scope, $stateParams) {
$scope.review = {};
$scope.review.rating = 3;
});
The module is loaded in a separate file:
angular.module('myapp.controllers', ['ionic.rating']).controller('AppCtrl', function($scope, $ionicModal, $timeout) {
...
Dayan's comment nailed it. I had the rating directive inside a label:
My Label
It works fine after removing it from inside the label.
I have a user.list.ctrl and a user.detail.cntr. All the controllers are build as a module and are injected in a "user-module" which I inject in the app.js. (see the complete code in the plunker below)
my controller module
angular.module('user-module', ['user-module.controllers']);
my user-module
angular.module('demo.app', ['user-module']);
In both controllers i inject user-Fctr with data from a REST factory. (works well)
user.list.cntrl has a $scope.refresh()
user.detail.cntrl has a $scope.update()
user.list.cntrl
When I enter a new record, i call the $scope.refresh() so I can refresh the list. (this is working fine)
user.detail.cntrl
When i click a user from the list, the user detail loads in a different view (works ok)
when I update the user.detail, I want to call $scope.refresh() to update the user.list , but it is not working. I cannot call $scope.refresh()
I thought that since I inject the same factory into both controllers I can use each others $scopes.
Any ideas on how I can use $scope.refresh() (or update the list when I update the user.detail.js)
I make a plunker with all the js files (the plunker is not functional, it is only to show the code that I have)
http://plnkr.co/edit/HtnZiMag0VYCo27F5xqb?p=preview
thanx for taking a look at this
This is a very conceptual problem.
You have created a controller for each "piece" of view because they are meant for different activities. This is the purpose of controllers. So that is right.
However, you are trying to access the refresh function, written in one controller, in another one. Taken literally, this is wrong, since then, refresh is out of place either inside the user list controller or the detail controller.
A function that is meant to control (literally) what is happening on a specific piece of view is a controller. - There you are right having a controller for the list and one for the details.
A function that is meant to be shared between controllers must be a service. This is exactly what you want for your refresh function to be.
Whenever you inject the same factory into n controllers, you can't use the scope of every controller. This isn't the purpose of a controller.
However, whenever you inject the same factory into n controllers, you can use its exposed methods.
The problem you have, can be solved as follows:
app.factory( 'sharedFunctions', [ 'factoryId', function sharedFunctions( factoryId ) {
var refresh = function () {
factoryId.getAll(/*your params to query*/)
.success( function ( response ) {
//This will return the list of all your records
return response;
});
};
return sharedFunctions;
}]);
With this factory service registered, then you can inject it to your controllers and whenever you need to refresh, just call the exposed method of the service and plot the new information into the view.
Hope it works for you!
i ended up doing this:
I added in the list.contrl this:
factoryId.listScope = $scope;
since I already have the factoryId (my data service) injected in the detail controller, I can call this:
factoryId.listScope.refresh();
it works but I don't know if this is the best way. any comments?
Google is indexing my Angular.js app's content just fine, i.e. it executes the JS, XHRs, the whole deal, but for some reason the title is not indexed properly and remains the static HTML fallback (default title set by HTML, before JS is executed).
In index.html I have:
<title ng-bind="title + ' — Default Title'">Default Title</title>
and it's set like this whenever the route changes:
app.run ['$location', '$rootScope', ($location, $rootScope) ->
$rootScope.$on '$routeChangeSuccess', (event, current, previous) ->
$rootScope.title = current.$$route.title if current.$$route
]
Example of the page: http://registerzdravil.si/zdravila/aspirin-protect-100-mg-gastrorezistentne-tablete
TL;DR: Google indexes my Angular app just fine, but doesn't index dynamic titles for some reason.
I am fairly sure you do not have much control over this. here are some links:
http://www.hobo-web.co.uk/title-tags/
https://yoast.com/google-page-title/
They both explain that:
Basically, Google says: we know better, you can try and write a title
we like, but we reserve to do whatever to make people click on your
result. There is no way to prevent this from happening right now.
Final Solution? It looks like I had my routing and controllers a little confused. I had my routing in a file with my controller module. I moved my routeProvider into the main module, like in the tutorial example. My controller and my routeProvider where under the same module. Maybe that was confusing everything. So now I have the controller in it's own module, and the routeProvider is under the main module. That seems to have fixed the problem without needing to initialize the search field to force the bindings to update the data.
Update:
The solution to showing my data at the time the page loads was to use an older version of angularJs, or use ng-Init and initialize the search field to a blank space.
I'm getting JSON data from the firebase website to update a table. I have a search field that works. The data will not display in the table until I type something into the search field. I don't know why the data won't just display in the table as soon as the controller is done getting the data.
Note: The link to the backend data is now removed, I don't want to keep that database file there indefinitely.
Here is the link to the jsFiddle code:
Last Version jsFiddle
Here is code for the controller.
'use strict';
/* App Module */
// Create the module named 'testApp'
var testApp = angular.module('theTestApp', [
'ngRoute',
'testServices'
]);
'use strict';
/* Services */
var testServices = angular.module('testServices', []);
testServices.controller('CommonController',
// function($scope, $http, $route) {
function($scope, $http) {
//access the customInput property using $route.current
//var dbKey = $route.current.customInput;
var dbKey = 'test-a-db-12345';
var urlToDb = 'https://' + dbKey + '.firebaseio.com/rows/.json';
$http.get(urlToDb).success(function(data) {
$scope.UsedItems = data;
});
});
How do I get the data to display as soon as it's loaded?
Update 1: I'm assuming that the data is already there, but the event of typing something into the search field triggers the filter, and then the data shows up. It shows up filtered.
Update 2: I'm reading about $Watch There is constantly and event loop listening for events. When a key is pressed in the search box, the bindings {{name}} get updated if something has changed. In this case, the content of the search input field was changed. So the issue seems to have something to do with when the bindings get updated, not whether the data is getting retrieved.
Update 3:
This version of the code runs. It loads the data when the page is rendered. Here is a working example in jsBins.
Update 4:
As of angularJs version 1.2.0 the behavior changes. Versions 1.0.8, 1.0.7 will instantly display my data when the page loads, 1.2.0 will NOT! I just happened to be using jsBins which uses 1.0.7, and it started working. Didn't know why until I started comparing the differences. Hopefully, there is a way to make it work in newer versions.
jsBins Working Example
The problem is that theSearch.Txt is empty. And you are filtering by that. My guess is that Angular at that moment decides to not let anything through and thus doesn't display anything.
What you should do:
Initialize the variable with a space filled string. (i.e. ' ')
Here is a working jsFiddle.
I used ngInit here. But that is because you decided to link?? the controller instead of putting it into a script tag. I suggest that next time you rather take the additional effort into pasting it in, as using the ngInit directive makes me feel like using eval.
Try
$scope.$apply(function(){
$scope.UsedItems=data;
}