Using select(name).options in Angular E2E test - javascript

I have a multi-value selector, which I am trying to write an E2E test for. Using select(name).option works fine, but when I try to use select(name).options to select multiple values it doesn't work.
I tried to put together some code together to demonstrate, but can't get it working.
HTML:
<html lang="en">
<head>
<title>End2end Test Runner</title>
<script src="http://code.angularjs.org/1.0.1/angular-scenario-1.0.1.js"
ng-autotest>
</script>
</head>
<body ng-app="MyApp">
<div ng-controller="MyAppCtrl">
{{model.exampleValue}}
<select id="a_selector"
ng-model="model.selectedItems"
ng-options="item.name for item in model.items"
multiple="multiple">
</select>
</div>
</body>
Javascript:
var app = angular.module('MyApp', ['ngResource'])
app.controller('MyAppCtrl', function($scope) {
$scope.model = {};
$scope.model.exampleValue="an example value";
$scope.model.items = [{"name": "Product1"}, {"name": "Product2"}];
});
app.config(['$routeProvider', function ($routeProvider, $scope) {
$routeProvider.when('/', {controller:MyAppCtrl});
}]);
describe('my app', function() {
it('should display the home page', function() {
browser().navigateTo('/');
// this should work (when I can fix this code!)
select("model.selectedItems").option("Product1");
expect(element("#a_selector option:selected").count()).toEqual(1)
// this doesn't, nothing is selected
select("model.selectedItems").options("Product1", "Product2");
expect(element("#a_selector option:selected").count()).toEqual(2)
});
});
The line
select("model.selectedItems").option("Product1");
fails with error message:
Selector select[ng\:model="model.selectedItems"] did not match any elements.
I'd appreciate it if someone can (1) help me identify why the above code isn't working at all, and (2) help me understand why select(name).options isn't working. (I know there are other techniques I could use to achieve the same thing, but the real select in the production code also has an ng-change attribute which does not fire when I try the workarounds).
Thanks,
Graeme Ludwig.

I am still trying to figure out why the select(name).option() is not working but I could get your example working by the following modifications:
Include angular.js before angular-scenario.js
Take out ngResource dependency - you don't need it here
Put <span>{{model.selectedItems}}</span> after your <select> tag to see what you have chosen.
I will update once I figure out the second part.

Shouldn't select("model.selectedItems").option("Product1"); be select("#a_selector").option("Product1"); instead?

Related

How to apply the AngularJS controller to the included page using ng-include

I have two html pages, main.html and nested.html, so the nested.html is actually included in main.html, this way:
main.html starts
<div ng-include src="'nested.html'"></div>
main.html ends
FULL CODE
nested.html
<html>
<h1> I am included, but controller not sending the values to me. </h1>
<input type="text" id="myDatePicker"/>
</html>
main.html
<html ng-controller="MainCtrl">
<h1> I am main.html and controller working properly on me, please take care of my child **given below** </h1>
<div ng-include src="'nested.html'"></div>
</html>
Controller Code:
(function() {
'use strict';
angular.module('bootstrapApp').controller('MainCtrl', MainCtrl);
function MainCtrl($scope, $location, $http, $compile) {
$("#myDatePicker").datepicker({
orientation: 'left'
});
}
});
The Controller code makes the text field a datepicker using jquery. The input field is in nested.html page. If the controller works on the included page, the textfield becomes a datepicker. That's it
Please guide me through how do I apply the same controller MainCtrl to included nested.html page
Thanks.
There are 2 important things to mention here:
The controller scope of the MainCtrl is already applied to the included nested.html. You can review that in the following Plunker: https://embed.plnkr.co/cvILaL3VvnJ5c1YDHDT1/.
You shouldn't use a jQuery datepicker from out of a AngularJS controller. Instead use a datepicker, which is intended for AngularJS (e.g. angular-datepicker)
from what I can guess,you must be using $scope.someVar and you are trying to render it in ng-include. Try creating an obj inside the controller like below:
$scope.obj= {
someVar : 'Value'
};
and use it in ng-include i.e. nested.html as {{obj.someVar}}.
Update 1
As per your new update, try AngularJS datepicker and let me know.
Try to add controller into nested.html file like:
<div ng-controller="MainController">
<h1> I am included, but controller not sending the values to me. </h1>
<input type="text" id="myDatePicker"/>
</div>
And from your comment:

Angular JS: data binding with dynamically added html elements

I am facing problems with two way data binding in angular js. Here is the sample code.
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
</head>
<body ng-app="">
<div>
<p>Input something in the input box:</p>
<p>Name: <input type="text" ng-model="name"></p>
<div id="jack">
</div>
<script>
$("document").ready(function(){
$("#jack").append("<p ng-bind='name'></p>");
});
</script>
</body>
</html>
Over here I am dynamically adding a paragraph with ng-bind to a div called jack using jQuery
For some reason when I type something in input box it is not reflecting in paragraph with ng-bind property.
I am a novice in angular js and would request you to provide me a simple solution to tackle this issue.
You cannot use jQuery to modify DOM outside Angular this way. Angular does not know about that binding as it was not compiled by Angular.
To solve this particular sample, simply remove the jQuery script and change the HTML to this:
<p>Input something in the input box:</p>
<p>Name: <input type="text" ng-model="name"></p>
<p ng-bind="name"></p>
The example above will work, but I imagine this was not a real-world example. If you post a more specific scenario, I can update my answer to help you solve that.
Edit
Based on your comment, I would create a simple directive to which you could pass your template, it would compile the template and inject the compiled template in the DOM.
Directive:
function myTemplateCompile($compile) {
return {
restrict: 'E',
link: link
}
function link(scope, elem, attrs) {
attrs.$observe('template', (template) => {
elem.html(template);
$compile(elem.contents())(scope);
});
}
}
HTML
<my-template-compile template="any HTML you might need including bindings"></my-template-compile>
You can then change the template attribute of the directive on the fly and it will re-compile and update the DOM based on the new value.
The example above should point you in the right direction. I just have to warn you, that this might be quite dangerous. If the content you are injecting is coming from some user input, this might have very severe security implications. Please make sure you are not exposing your application to attacks.
Well first we need to define the app and create custom directive.
var myApp=angular.module('myApp',[])
.controller('myCtrl',function($scope){
$scope.name="Your name";
})
myApp.directive('myDirective', function() {
return {
restrict: 'E',
template: '<span data-ng-bind="name"></span>'
};
});
After this you need to use above created directive as like below
<my-Directive></my-Directive>

Angular is not displaying data in table row. ng-repeat is not working

I'm trying to use Angularjs. The problem is, ng-repeat not working when it is in the route. It works when it is not in route.
Here's what I have so far:
See the links..
this works well...
http://plnkr.co/edit/1syQFJdMyRUYncBrREue?p=preview
but in this, it didn't work now..(navigate in persons)
http://plnkr.co/edit/gsi2mZpnU0YJUUOa20DO?p=preview
html
<html ng-app="myApp">
<head>
<title>Confirm Dialog Box</title>
<!--
in the link above i create a custom dialog box
-->
</head>
<body>
<div ng-controller="loglistController">
<table>
<tr ng-repeat="x in names">
<td onclick="showDialog()" ng-click="showInEdit(x)">{{ x.Name }}</td>
<td onclick="showDialog()" ng-click="showInEdit(x)">{{ x.Country }}</td>
</tr>
</table>
<div id="white-background">
</div>
<div id="dlgbox">
<div id="dlg-header"><h3>Information</h3></div>
<div id="dlg-body">
Name <input type="text" ng-model="selectedPerson.Name" /><br/>
Country <input type="text" ng-model="selectedPerson.Country" /><br/>
</div>
<div id="dlg-footer">
<button onclick="dlgOK()">Update</button>
<button onclick="dlgCancel()">Exit</button>
</div>
</div>
angular
var myApp = angular.module('myApp', ['ngRoute']);
myApp.controller('loglistController', ['$scope', '$http', function ($scope, $http) {
$scope.data=[];
$scope.selectedPerson={ Name:"",Country:""};
$http.get("loglistajax.php")
.then(function (response) {$scope.names = response.data.records;});
$scope.showInEdit=function(person){
$scope.selectedPerson = person;
};
}]);
Here is my version
I agree with most points that imbalind mentioned.
Just would like to add few more:
we should not instantiate same app multiple times (in original Plunker we had it in both index.html and list.html). Here are two cases:
var myApp = angular.module('myApp', ['ngRoute']); //new instance of 'myApp'
var myApp = angular.module('myApp'); //simply handle to 'myApp'
we had two 'loglistController' that belong to same angular.module, which not going to work
angular itself was loaded in both html files, not good.
for that particular Plunker, fixed route in app.js:
.when('/', {
templateUrl: '/index.html',
controller: 'mainController'
})
and please don't mixup jQuery script, it will create a lot of confusion later...
Here is a (somewhat) fixed plunker, however I found the following issues in your code:
You have double controllers: loglistController is defined twice, once inside app.js and then again inside list.html.
You wrote the following line
<tr ng-repeat="x in data">
Thinking it would read from loglistController's $scope.data but your app seems to be considering the first controller, so your controller scope has no data properties. I solved replacing the controller in app.js with the one inside list.html.
Thinking about it, I guess you are not allowed to put a route controller's code inside it's template, so you'd better avoid doing that in the future!
Your app.js' templateUrl does not exists when url is '/' and this throws an error. I solved by replacing it with 'list.html'. I'm quite sure it's not what you will want, but it was needed to make it work.
are you sure your $http request is resolving?
$http.get("loglistajax.php").then(function (response) {
$scope.names = response.data.records;
}).catch(function(response) {
console.log("I am failing to resolve a non-2xx response");
});
initially try without the $http request using dummy data n build up slowly!
FYI ...
you can do ...
$scope.names = $http.get("loglistajax.php");
Which only works if the HTTP request resolve!
PS neither of your plunkr's show anything!

Angular JS and ng-model not displaying

I am a newbie at Angular JS and this is what I started with:
var myApp = angular.module('myApp', []);
myApp.controller('WizardController', ['$scope', function($scope){
$scope.user = {};
$scope.displayName = 'Hello';
}]);
user is used to gather the data in the input fields in my steps <input type='text' ng-model='user.name'> and when I call it like so {{user.name}} what is inside the input text appears in a next step.
My question is how do I get $scope.displayName to display on my page.
<p ng-model="displayName"></p>
<p>{{displayName}}</p>
<p><input type='text' ng-model='displayName'></p>
I have tried all of these and none seem to work. Please help.
here is a jfiddle http://jsfiddle.net/Fc7KZ/
Make sure you added the ng-app and ng-controller attributes to your html
<body ng-app="myApp" ng-controller="WizardController">
<p ng-model="displayName"></p>
<p>{{displayName}}</p>
<p><input type='text' ng-model='displayName'></p>
</body>
Update 1:
Your js fiddle did not have angular library here is the version corrected:
http://jsfiddle.net/Fc7KZ/2/
You seem to be using angular-wizard. Your Fiddle doesn't include Angular or Lodash, which are both pre-requisites of that project. I'm guess your local code doesn't either, if not then that's your problem.

Bind checkbox or multi-select dropdown to array in AngularJS?

I am new to AngularJS, and am thus confused as how to bind checkboxes or multi-select dropdowns to a separate list.
<body ng-controller="FooListCtrl">
<span ng-repeat="foolist in foos">
<select ng-model="selected" ng-options="foo for foo in foolist" multiple="">
</select>
</span>
</body>
'use strict';
function FooListCtrl($scope) {
$scope.foos = {"Bar": [ "foo", "bar"]};
$scope.selected = [];
}
FooListCtrl.$inject = ['$scope'];
Run the code: http://jsfiddle.net/gBcN2/
If I got right what you want:
You don't have ng-app definition.
On jsFiddle for snippets of AngularJS put No wrap - in <head> load mode, if you are using AngularJS as external resource.
Model selected has it's own "range", because you use ng-repeat. To see what I mean, here is fixed version of your code:
http://jsfiddle.net/gBcN2/2/
First {{selected}} works fine, but second is "outside" of ng-repeat scope.
PS:
You don't have to use ng-repeat if you want to use it like you wrote in your example: quick fiddle of how I'd do it.
Edit:
For checkboxes it's something like that - http://jsfiddle.net/qQg8u/2/

Categories

Resources