Folowing the angular railscasts tutorial I have a rails app with angularjs-rails,
both angular.js and angular-resource.js are being included in the head of my html file.
my welcome#index.html.erb is:
<h1>Welcome</h1>
<div id="search" ng-controller="SearchCtrl">
<form ng-submit="search()">
<input type="text" ng-model="newSearch.postcode">
<input type="submit" value="Search">
</form>
<ul>
<li ng-repeat="trader in traders">
{{trader.name}}
</li>
</ul>
</div>
and my welcome.js.coffee:
app = angular.module("Search", ["ngResource"])
#SearchCtrl = ($scope, $resource) ->
$scope.traders = [
{name: "Jonlee"}
{name: "Johnny"}
]
$scope.search = ->
console.log($scope.newSearch.postcode)
For some reason the resource is not working, I am receiving the below error:
[$injector:unpr] Unknown provider: $resourceProvider <- $resource
Have googled around and have seen this error but in much more complicated examples that don't really fit this problem.
Application.js:
//= require angular
//= require angular-resource
//= require_tree .
Exported welcome.js:
(function() {
var app;
app = angular.module("Search", ["ngResource"]);
this.SearchCtrl = function($scope, $resource) {
$scope.traders = [
{
name: "Jonlee"
}, {
name: "Johnny"
}
];
return $scope.search = function() {
return console.log($scope.newSearch.postcode);
};
};
}).call(this);
Related
I am a newcomer to angularjs and am incredibly confused as to how data-binding and dependency-injection work.
To test if the code works, I created a test expression, 5+5. It works if I don't inject dependencies inside the module, but doesn't if I inject one.
I am working with Ruby on Rails. Here is the example code
Welcome.index.erb
<div class="col-md-4 col-md-offset-2">
<ul class="list-inline" ng-app="my-app" ng-controller="HomeCtrl">
<li><a ng-href="/api/auth/sign_in">Sign In</a></li>
<li><a ng-href="/api/auth/sign_up">Sign Up</a></li>
<li>Help</li>
<li>{{5+5}}</li>
</ul>
</div>
<script>
angular.module("my-app", [])
.controller("HomeCtrl", function($scope) {
$scope.number = 1;
});
</script>
This works, tested by the data-binding expression {{5+5}} evaluating to 10. However, if I add a dependency injection to my module
angular.module("my-app", ['ngRoute'])
.controller("HomeCtrl", function($scope) {
$scope.number = 1;
});
.controller("UserRegistrationsCtrl", ['$scope', function($scope) {
});
.controller("UserSessionsCtrl", ['$scope', function($scope) {
});
.config(['$routeProvider', function($routeProvider) {
$routeProvider
.when('/', {
templateUrl: 'views/welcome/index.html.erb',
controller: 'HomeCtrl'
})
.when('/sign_in', {
templateUrl: 'views/user_sessions/new.html',
controller: 'UserSessionsCtrl'
})
.when('/sign_up', {
templateUrl: 'views/user_registrations/new.html',
controller: 'UserRegistrationsCtrl'
})
.otherwise({
redirectTo: '/'
});
}]);
the data-binding looks like it gets broken, and the list item gets rendered as {{5+5}}.
user_sessions/new.html
<form ng-submit="submitLogin(loginForm)" role="form" ng-init="loginForm = {}">
<div class="form-group">
<label for="email">Email</label>
<input type="email"
name="email"
id="email"
ng-model="loginForm.email"
required="required"
class="form-control">
</div>
<div class="form-group">
<label for="password">Password</label>
<input type="password"
name="password"
id="password"
ng-model="loginForm.password"
required="required"
class="form-control">
</div>
<button type="submit" class="btn btn-primary btn-lg">Sign in</button>
</form>
user_registrations.html
<form ng-submit="handleRegBtnClick()" role="form" ng-init="registrationForm = {}">
<div class="form-group">
<label for="email">Email</label>
<input type="email"
name="email"
id="email"
ng-model="registrationForm.email"
required="required"
class="form-control">
</div>
<div class="form-group">
<label for="password">Password</label>
<input type="password"
name="password"
id="password"
ng-model="registrationForm.password"
required="required"
class="form-control">
</div>
<div class="form-group">
<label for="password_confirmation">Password confirmation</label>
<input type="password"
name="password_confirmation"
id="password_confirmation"
ng-model="registrationForm.password_confirmation"
required="required"
class="form-control">
</div>
<button type="submit" class="btn btn-primary btn-lg">Register</button>
</form>
Not sure why the data-binding was broke. Any help will be appreciated.
Update
I went into the Console in Chrome Developer Tools, and ran a couple commands
var listElement = document.querySelector('ul')
listElement
=><ul class="list-inline" ng-app="my-app" ng-controller="HomeCtrl">...
listElement.controller();
=>TypeError: undefined is not a function
listElement.injector();
=>TypeError: undefined is not a function
Here are the scripts I'm using
<script src="/assets/jquery-7f1a72dc175eaa60be2e692ab9e6c8ef.js?body=1"></script>
<script src="/assets/jquery_ujs-68ce8f5ee2895cae3d84a114fdb727e1.js?body=1"></script>
<script src="/assets/bootstrap-3dfec047bf3f975670c20b5e35a5f42e.js?body=1"></script>
<script src="/assets/angular/angular-8bf873ad356fbb7267e223d5cac348f5.js?body=1"></script>
<script src="/assets/angular-8bf873ad356fbb7267e223d5cac348f5.js?body=1"></script>
<script src="/assets/angular-cookie/angular-cookie-79e90f9112d0e1bf9aede30a4b7f5d36.js?body=1"></script>
<script src="/assets/angular-cookie-79e90f9112d0e1bf9aede30a4b7f5d36.js?body=1"></script>
<script src="/assets/angular-bootstrap/ui-bootstrap-tpls-2d5fe21018866bf67cca9784e2ae95a9.js?body=1"></script>
<script src="/assets/angular-bootstrap-2d5fe21018866bf67cca9784e2ae95a9.js?body=1"></script>
<script src="/assets/angular-messages/angular-messages-f8b337aaacde7f3ee4d9fd590f36749a.js?body=1"></script>
<script src="/assets/angular-messages-f8b337aaacde7f3ee4d9fd590f36749a.js?body=1"></script>
<script src="/assets/angular-resource/angular-resource-79e25fff913ab31c097086ac463d7d41.js?body=1"></script>
<script src="/assets/angular-resource-79e25fff913ab31c097086ac463d7d41.js?body=1"></script>
<script src="/assets/angular-ui-router/angular-ui-router-1c9044ef4d22b7d3b266e72a34c275ea.js?body=1"></script>
<script src="/assets/angular-ui-router-1c9044ef4d22b7d3b266e72a34c275ea.js?body=1"></script>
<script src="/assets/angular-ui-utils/ui-utils-895ce7dcab9d6b51db05d3816862b02c.js?body=1"></script>
<script src="/assets/angular-ui-utils-895ce7dcab9d6b51db05d3816862b02c.js?body=1"></script>
<script src="/assets/ng-token-auth/ng-token-auth-1e86f8812a656893f8b8ee6fe807290d.js?body=1"></script>
<script src="/assets/ng-token-auth-1e86f8812a656893f8b8ee6fe807290d.js?body=1"></script>
<script src="/assets/angular/app-b06dbf3801b44bee508a1fea1255119d.js?body=1"></script>
<script src="/assets/application-b2f074707bb9272eab9330966cfe5014.js?body=1"></script>
My application.js.coffee
#= require jquery
#= require jquery_ujs
#= require bootstrap
#= require angular
#= require angular-cookie
#= require angular-bootstrap
#= require angular-messages
#= require angular-resource
#= require angular-ui-router
#= require angular-ui-utils
#= require ng-token-auth
#= require_tree
For one thing, you are placing semi-colons where you shouldn't be. You are breaking your method chains.
angular.module('my-app', ['ngRoute'])
.controller('HomeCtrl', function($scope) {
...
})
.controller('UserRegistrationsController', ['$scope', function($scope) {
...
}])
.controller('UserSessionsController', ['$scope', function($scope) {
...
}])
.config(['$routeProvider', function($routeProvider) {
...
}]);
I don't know that this would be your entire issue, but update your code accordingly, look at your console and report the errors coming out there.
The problem was related to my Gemfile and Assets. I had the following gem installed
gem "rails-assets-angular-ui-router"
I needed to add
gem "rails-assets-angular-route"
then add
#= require angular-route
to my application.js.coffee file
I mostly followed Ryan Bates' setup for a angular app in rails. In my gemfile:
gem 'angularjs-rails'
and in the application.js:
//= require angular
//= require angular-resource
//= require turbolinks
//= require_tree .
Here is what I believe is all the relevant code from views/pages.home.html:
<body data-ng-app="dithat">
<div class="container" data-ng-controller="accomplishmentController">
<p> What'd you do? </p>
<form ng-submit="submit()">
<input type="text" ng-model="newAccomp" />
</form>
<div data-ng-repeat="accomp in accomplishments | filter:newAccomp" >
<div class="box" ng-click="addToCount()">
<div class="accomplishment">
{{ accomp.name }}
x
<p class="count"> {{ accomp.count }} </p>
</div>
</div>
</div>
</div>
<script type="text/javascript">
app = angular.module("dithat", ["ngResource"]);
function accomplishmentController($scope, $resource) {
Entry = $resource('/api/users.json');
console.log(Entry.query());
$scope.accomplishments = [];
$scope.submit = function() {
$scope.accomplishments.unshift({ name: $scope.newAccomp, count: 0 });
$scope.newAccomp = '';
}
$scope.addToCount = function() {
var currentcount = this.accomp.count;
this.accomp.count = currentcount + 1;
}
$scope.delete = function() {
index = this.$index;
$scope.accomplishments.splice(index, 1)
}
}
</script>
</body>
The code works, as in the app is behaving how it should, however it is not making the resource call. I tried this with $http as well and it didn't work either. What am I missing??!! Thanks a lot!
As per comment:
The accomplishmentController function is defined but it still needs to be registered with angular using
app.controller('accomplishmentController', accomplishmentController)
otherwise it will not be able to be used (and won't necessarily cause any errors).
I am having a strange problem. I am using AngularJS in my project. I have some partial views where I am having different implementations of AngularJS functionality. I am loading all my partial views via Ajax call. Ajax call does load partial view in container but its AngularJS functionality does not work. I have noticed that when I give reference to AngularJS via CDN then it works but when I copy and paste CDN JS into my local js file then it does not.
Please suggest what is the issue.
Here is the code:
Partial View:
<div ng-controller="EmployeeController">
<div>
ID: <input type="text" id="txtID" ng-model="employeeID" /><br />
Name: <input id="txtName" type="text" ng-model="employeeName" />
<button id="btnAddEmployee" ng-click="addEmployee()">Add Employee</button>
<button id="btnRemoveEmployee" ng-click="removeEmployee()">Remove Employee</button>
<ul >
<li ng-repeat="employee in employees">
Employee id is: {{employee.id}}<br />
Employee name is: {{employee.name}}
</li>
</ul>
</div>
</div>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js"></script>
<script>
var employees = [{ name: 'ABC', id: '1' },
{ name: 'XYZ', id: '2' },
{ name: 'KKK', id: '3' }];
function EmployeeController($scope) {
$scope.employees = employees;
$scope.addEmployee = function () {
$scope.employees.push({ name: $scope.employeeName, id: $scope.employeeID });
}
$scope.removeEmployee = function () {
$scope.employees.pop();
}
}
</script>
Controller:
public PartialViewResult LoadViews(int id)
{
if (id == 1)
return PartialView("TestView1Partial");
else
return PartialView("TestView2Partial");
}
Main View:
<ul>
<li>
View 2
</li>
</ul>
<div id="dvContainer">
<script>
function LoadView2() {
$.ajax({
url: "/home/LoadViews?id=2",
type: "GET",
datatype: "html",
async:true,
success: function (result) {
$("#dvContainer").html(result);
}
});
}
</script>
Thanks,
JSHunjan
In your Ajax call change the async:false and it might work.
I dropped in my angular app into a new ruby on rails app. what i'm noticing is that no views are being rendered out. i only see the layout being rendered. also i'm not getting any errors. my 2 views (home.html and about.html) and list.json are located in the public folder. please let me know if you need any more code from the app.
i have my application layout as follows:
<!DOCTYPE html>
<html>
<head>
<title></title>
<%= stylesheet_link_tag "application", :media => "all" %>
<%= javascript_include_tag "application" %>
<%= csrf_meta_tags %>
</head>
<body>
<div class="navbar navbar-inverse navbar-fixed-top">
<div class="navbar-inner">
<div class="container">
<button data-target=".nav-collapse" data-toggle="collapse" class="btn btn-navbar" type="button">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<img src="assets/tool-box.png" /> Dev Tool Chest
<div class="nav-collapse collapse">
<ul class="nav">
<li class="active">
Home
</li>
<li class="">
About
</li>
</ul>
</div>
</div>
</div>
</div>
<div class="container">
<div id="view" ng-view></div>
</div>
</body>
</html>
i have my application controller as follows:
class ApplicationController < ActionController::Base
protect_from_forgery
def index
render :layout => 'application', :nothing => true
end
end
I've made my JS asset pipeline as follows:
//= require jquery
//= require jquery_ujs
//= require bootstrap
//= require angularmin.js
//= require angularstrap.min.js
//= require toolsapp.js
the toolsapp.js looks like this
var tools = angular.module("tools", ['$strap.directives'])
tools.config(function($routeProvider) {
$routeProvider.when('/home', {
templateUrl: 'home.html',
controller: 'HomeController'
});
$routeProvider.when('/about', {
templateUrl: 'about.html',
controller: 'AboutController'
});
$routeProvider.otherwise({ redirectTo: '/home' })
});
tools.controller("HomeController", function($scope, fetchData) {
fetchData.then(function(data){
$scope.record = data;
$scope.typeahead = function(){
var allNames = [];
for(var i=0;i<$scope.record.length;i++){
allNames.push($scope.record[i].name)
}
return allNames;
}
});
$scope.clearSearch = function(){
$scope.search = "";
$scope.name2 = "";
}
$scope.name2 = "";
$scope.search = "";
});
tools.controller("AboutController", function($scope) {
});
tools.factory('fetchData', ['$http', function($http){
var Url = "list.json";
var list = $http.get(Url).then(function(response){
return response.data;
});
return list;
}]);
tools.filter('unique', function () {
return function (items, filterOn) {
if (filterOn === false) {
return items;
}
if ((filterOn || angular.isUndefined(filterOn)) && angular.isArray(items)) {
var hashCheck = {}, newItems = [];
var extractValueToCompare = function (item) {
if (angular.isObject(item) && angular.isString(filterOn)) {
return item[filterOn];
} else {
return item;
}
};
angular.forEach(items, function (item) {
var valueToCheck, isDuplicate = false;
for (var i = 0; i < newItems.length; i++) {
if (angular.equals(extractValueToCompare(newItems[i]), extractValueToCompare(item))) {
isDuplicate = true;
break;
}
}
if (!isDuplicate) {
newItems.push(item);
}
});
items = newItems;
}
return items;
};
});
My suggestion for this is:
Create a home controller:
home_controller.rb
class HomeController < ApplicationController
def index
end
def about
end
end
Move your views to app/views/home folder.
Add following routes:
routes.rb
get 'about', to: "home#about"
root to: 'home#index'
Remove from application_controller:
def index
render :layout => 'application', :nothing => true
end
And add a yield in your layout:
<div class="container">
<div id="view" ng-view>
= yield
</div>
</div>
So, your home and about views are gonna be rendered inside your layout when you go to localhost:3000 and localhost:3000/about.
Why am I getting this error: Selector [ng\:model="query"] did not match any elements
I've read through this: AngularJS: End to End Testing Issue , but that link doesn't really apply in a .net env:
IDE: Visual Studio 2012
Project type: ASP.NET MVC4
File strucure:
Running CI tests through karma start e2e.conf.js in node.js command prompt
My karma conf:
basePath = '../../../';
files = [
ANGULAR_SCENARIO,
ANGULAR_SCENARIO_ADAPTER,
'angular/app/*.js',
'angular/Tests/e2e/*.js'
];
reporters = ['progress'];
port = 10876;
runnerPort = 10100;
colors = true;
logLevel = LOG_ERROR;
autoWatch = true;
browsers = ['Firefox'];
captureTimeout = 60000;
singleRun = false;
proxies = {
'/': 'http://localhost:60607/'
};
My e2e test:
describe('E2E: AMS', function () {
describe('Settings Users', function () {
beforeEach(function () {
browser().navigateTo('/#/settings/users');
});
it('filters the users list as the user types into the search box', function () {
expect(repeater('.users li').count()).toBe(2);
input('query').enter('abc');
expect(repeater('.users li').count()).toBe(1);
input('query').enter('efg');
expect(repeater('.users li').count()).toBe(1);
input('query').enter('ijk');
expect(repeater('.users li').count()).toBe(0);
});
});
});
My View:
<div data-ng-view="">
Add User: <br />
<input type="text" /> <button>Submit</button><br />
Search:
<input data-ng-model="query" type="text" />
Users <br />
<ul class="users">
<li data-ng-repeat="user in users | filter:query">
{{user.name}}
</li>
</ul>
</div>
and for grins, my route
angular.module('AMS', []).
config(['$routeProvider', function ($routeProvider) {
$routeProvider.
when('/login', { templateUrl: '/AccessControl/Login/', controller: settingsController }).
when('/dashboard', { templateUrl: '/Dashboard/Dashboard', controller: dashboardController }).
when('/settings', { templateUrl: '/Settings/Settings', controller: settingsController }).
when('/settings/users', { templateUrl: '/Settings/Users', controller: settingsController }).
otherwise({ redirectTo: '/dashboard' });
}]);
It looks like the angular e2e testing api is looking for "ng-model" in your view instead of the "data-ng-model" that you're using.
My understanding is that both are valid, but give that a try to see if that's the problem.
Not an answer, so I wont mark it as such, this is more of a work around.
I've decided to go with chutzpah in order to run the jasmine unit tests, and specflow.xunit for "e2e" testing. It works well in a .net environment and integration into teamcity seems straight forward.