AngularJs testing. Where to put template - javascript

I am currently testing an angularjs directive. This directive has a templateUrl. I would lke to test the view to make sure it was initialized correctly i.e. correct number of buttons, certain elements hidden.
The problem I am having is that when I insert my html file into the template cache I still get :
"message": "Unexpected request: GET partials/stuff/stuff-leader.html
I assumed that when I used the templateCache I would no longer have to use:
$httpBackend.whenGET("partials/stuff/stuff-leader.html").respond([{
userId: 000
}]);
but this does not seem to be the case. I am wondering am I correctly inserting the template, here is how I am doing it:
template = $templateCache.get('/full/root/disk/path/to/file/stuff/stuff-leader.html');
$templateCache.put('/myApp/templates/stuff-leader.html',template);
Is this correct, or should I be placing it somewhere else?

Your normal template is looked for at /partials/stuff/stuff-leader.html, so this is what you need to inject into the template cache instead of /myApp/templates/stuff-leader.html.

You are performing a request with the $templateCache.get. Instead do:
beforeEach(inject(function ($templateCache) { $templateCache.put('partials/stuff/stuff-leader.html', '< div >...TemplateCode....< /div >'); }));

Related

Compiling form inside AngularJS directive

I wrote an AngularJS directive with a form. The form has a required text field as well as two other forms. Each of them child forms has another required text field.
The difference between the 2 child forms is how I create them:
The first child form is compiled and appended to a div.
The second child form is directly included in the template of the directive.
If the second child form is invalid, the whole outter form becomes invalid. This is what I expected. However, if the first child form (the one I compiled manually) becomes invalid, it has no influence on the outter parent form. Why?
var app = angular.module('plunker', []);
app.component('generator', {
template: "<ng-form name=\"outterForm\">" +
"<input name=\"out\" ng-model=\"$ctrl.out\" ng-minlength=\"5\" ng-required=\"true\" type=\"text\" />" +
"<div id=\"component-container\"></div>" +
"<my-text></my-text>" +
"<div>Valid outterForm: {{outterForm.$valid}}</div>" +
"</ng-form>",
controller: function($compile, $scope, $document) {
var componentContainer = $document.find('#component-container');
var template = "<my-text></my-text>";
var childScope = $scope.$new();
var result = componentContainer.append(template);
$compile(result)(childScope);
}
});
app.component('myText', {
template: "<ng-form name=\"innerForm\"><input name=\"name\" ng-model=\"$ctrl.name\" ng-minlength=\"5\" ng-required=\"true\" type=\"text\" />Valid innerForm: {{innerForm.$valid}}</ng-form>"
});
Here's the running Plunker:
https://plnkr.co/edit/YfBRY4xPvKgqDtWXFMUi
That's because $$parentForm of sub-form's formController hasn't been set after you compile that sub-form. And I don't know why, it needs more deep knowledge I suppose.
I tried to $compile()() in different compilation stages (preLink, postLink) and had same result. However I almost achieve the goal with two methods:
First is to assign $$parentForm directly like this childScope.innerForm.$$parentForm = scope.outterForm;. Here is my plunker example (notice I changed components to directives, cause they are more flexible).
Second is to recompile parent form (but this makes useless manual sub-form compilation). Here is the second plunker example.
But! In both methods there is one huge problem - setting sub-forms names and models dynamically (it should be so, cause you want to use one directive on multiple sub-forms).
In first method there is no errors, but one bug: when you change model of the second sub-form it changes model of the first one (it stops when you once adjust model of the first sub-form).
In the second method everything seems to work fine, but at backstage there are a lot of errors occurs each time you change model.

Reload or reinitialize angular form after posting data

I have an angular form to add data in database.I am using angular-fullstack by yeoman.
Now, once data is posted, I can clear ty the form values by assigning an empty object to form scope.
However, I can not add more values without reloading the page.
Also, I have tried this:
var original = $scope.permission;
$scope.reset(original);
$scope.reset= function(original){
$scope.permission= angular.copy(original)
$scope.form2.$setPristine();
$scope.form2.$setUntouched();
}
But has not helped.
Note: $route.reload() is not suitable for me in this case therefore I am trying to find alternatives to do this.
That error seems to be relevant. If I understand correctly you are trying to inject ngRoute module as dependency into your createProjectApp. In that case you should do something like this:
angular.module('createProjectApp', ['ngRoute']);
and make sure you have proper script tag in the header:
<script src="angular-route.js">
Hope this helps.
I'm not sure what your requirements are. But as for $route.reload, I think you're injecting the module incorrectly. There are two things you need to do to get $route.reload() to work. After you've added angular-route.js as a script tag:
1) Change
angular.module('createProjectApp', ['$route'])
to
angular.module('createProjectApp', ['ngRoute'])
According to the documentation, the correct module name is ngRoute
https://docs.angularjs.org/api/ngRoute/service/$route
2) In your controller, you need to include $route as a parameter. Then you can use $reload.route() in that particular controller like so:
createProjectApp.controller('MainController', function ($scope, $route) {
$scope.reload = function(){
$reload.route();
}
}

Add AngularJS directive at runtime

I am creating a game where the first thing that needs to happen is some state is loaded in from an external JSON file - the contents of one of my directives are dependent on this data being available - because of this, I would like to delay applying the directive until after the data has loaded. I have written the following:
window.addEventListener('mythdataLoaded', function (e) {
// Don't try to create characters until mythdata has loaded
quest.directive('character', function() {
return {
restrict: 'A',
scope: {
character: '#'
},
controller: 'CharacterCtrl',
templateUrl: 'partials/character.html',
replace: true,
link: function(scope, element) {
$(document).on('click', '#'+scope.character, function () {
$('#'+scope.character+'-popup').fadeToggle();
});
}
};
});
});
// Load in myth data
var myth_data;
$.getJSON("js/mythdata_playtest.json", function(json) {
myth_data = json;
window.dispatchEvent(new Event('mythdataLoaded'));
});
However, it appears that my directive's link function never runs - I'm thinking this is because angular has already executed the part of it's cycle where directives are compiled/linked by the time this directive gets added. Is there some way to force angular to compile this directive after it is created? I googled around a bit, and some people suggested adding $compile to the link function for similar issues - but the link function is never run, so that doesn't work for this case. Thanks!
It seems to me it would be better to always configure the directive, to do the JSON call in the directive, and attach logic to the element in the JSON call's success handler. This would, if I understand you correctly, do what you want.
AngularJS is meant as a framework, not a library, so using it in the way you mentioned is not recommended. Exactly as you mentioned, AngularJS does a lot of things for you when it runs. AngularJS, by default, runs on document loaded, and your $.getJSON callback arrives after that. When AngularJS runs it does all its magic with compiling the content and all that.
As a sidenote, it's also more the Angular way to use $http over $.getJSON.
I think you're thinking about this the wrong way. A major ideology in angular is that you set up declarative elements and let it react to the state of the scope.
What I think you might want to do is pass in what you need through the directive scope, and use other angular built in directives to hide or show your default ("non directive") state until the scope gets set from the controller for example.
Example:
You want a box to be hidden until an api call comes back. Your directive sets special styles on your element (not hidden). Instead of delaying to dynamically set your directive, you can pass in a scope var with a default value and use something like ng-show="data.ready" in your directive template to handle the actual dom stuff.

AngularJS string interpolation not working?

For some reason, I can't seem to get string interpolation ({{}}) to work in my angularJS setup. I'm running with the MEAN stack I downloaded from here about a month ago and trying to replicate the angular-ui accordion example in my environment. In my template I have this:
<accordion close-others="true">
<accordion-group is-open="true" class="no-padding" ng-repeat="optSet in chartOptions">
<accordion-heading>{{optSet.name || 'broken...'}}</accordion-heading>
<div ng-include src="'option-content'" ng-init="options = optSet.data"></div>
</accordion-group>
</accordion>
then I have this in my controller:
$scope.chartOptions = [
{ 'name': 'Axis', 'data': chartAxisOptions }
];
but all I ever get is 'broken...' even though there's clearly a name attribute there as well. It's weird because it definitely renders based on the data I give it, but the name is not working at all. I have also tried adding it to the header attribute of the <accordion-group>, and making it check optSet['name'] as well -- the latter gives me undefined, in fact.
Unfortunately, the MEAN stack has some really weird setup issues. There was an issue with the Express twig templates, and angular interpolation. After making everything use angular, string interpolation worked again.

angularJs - won't show data until user types in search field

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;
}

Categories

Resources