$resource calls to url failing in simple angularjs app built in rails - ruby-on-rails

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).

Related

Rails + Angular : Issue with directive

I have Rails 4.2.4 and Angular 1.4.8.
I am trying define a directive:
index.html:
<div ng-app='myApp' ng-controller='myController'>
<foo bar='bar'></foo>
</div>
app.js:
angular.module('myApp', ['templates']);
angular.module('myApp', ['templates']).directive('foo', function(){
return {
restrict: 'AE',
scope: {
bar: '='
},
templateUrl: 'bar.html'
}
});
angular.module('myApp').controller('myController', function($scope, $http){
$scope.bar = "XMan";
});
bar.html:
<h1> Hi {{ bar }}! </h1>
<ng-include src="'{{bar}}.html'"
XMan.html:
<p>Hello I'm XMan</p>
Here I am expecting my foo directive to render
<h1> Hi X Man! </h1>
<p> Hello I'm XMan </p>
but I am getting
<h1> Hi {{ bar }}! </h1>
<!-- ngInclude: undefined -->
What is wrong with my approach. Please guide me; I am very new to Angular.js.
I got a solution. We cannot bind ng-include src with scope variable.
Instead I used function call to get the source then it works!
That is I changed
<ng-include src="'{{bar}}.html'"
to
<ng-include src="barUrl()"
and added a controller scope function:
$scope.barUrl = function(){
return $scope.bar + '.html'
}

angularjs - Adding dependencies breaks data binding

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

Multiple selection in angular bootstrap typeahead

Is it possible to select multiple values from angular ui bootstrap typeahead?
http://angular-ui.github.io/bootstrap/#/typeahead
Hi without changing the codebase probably not - you could try https://github.com/rayshan/ui-multiselect
I recently had the same requirement and was able to solve it by overriding the internal bootstrap implementation via an alternate popup-template. I created a new directive (multi-select-typeahead) to encapsulate the change.
The template uses an ng-init to pass the scope reference (of the typeahead popup directive) to the multi-select-typeahead directive. There the directive overrides the parent's scope. $scope.$parent in this case is the bootstrap typeahead directive itself. The custom directive provides a new implementation of select() which is called internally by angular bootstrap. The new implementation prevents the popup from closing and removes selected items from the list.
The alternate popup I provided is almost entirely the same as the default angular bootstrap typeahead template "uib/template/typeahead/typeahead-popup.html". The only modification was the addition of the ng-init which passes its scope to the multi-select-typeahead directive.
I'm sure if you are clever enough you could render the angular bootstrap default template by reference and inject the ng-init part, removing the duplicated bootstrap code. This would make the solution a bit more resilient to future angular bootstrap changes. That being said, the solution is already quite a hack and is prone to breaking in future major releases.
Hope this is useful to someone!
angular.module('typeahead.demo', [
'ngAnimate',
'ngSanitize',
'ui.bootstrap'
]);
angular
.module('typeahead.demo')
.controller('TypeaheadDemo', TypeaheadDemo);
function TypeaheadDemo($scope) {
$scope.addItem = addItem;
$scope.itemApi = itemApi;
$scope.items = [];
function addItem(item) {
$scope.items.push(item);
}
function itemApi() {
return [
{ name: 'apple' },
{ name: 'orange' },
{ name: 'grape' }
];
}
}
angular
.module('typeahead.demo')
.directive('multiSelectTypeahead', multiSelectTypeahead);
function multiSelectTypeahead() {
return {
templateUrl: 'multi-select-typeahead.html',
scope: {
searchApi: '&',
displayNameField: '#',
onSelect: '&',
inputPlaceholder: '#?'
},
link: function ($scope) {
var uibTypeaheadScope;
$scope.initializeScope = initializeScope;
$scope.$watch('isOpen', function (newValue) {
if (!newValue) {
$scope.searchTerm = '';
}
});
function initializeScope(typeaheadPopupScope) {
uibTypeaheadScope = typeaheadPopupScope.$parent;
uibTypeaheadScope.select = selectItem;
}
function selectItem(index, event) {
var selectedItem = uibTypeaheadScope.matches[index].model;
event.stopPropagation();
if (event.type === 'click') {
event.target.blur();
}
uibTypeaheadScope.matches.splice(index, 1);
$scope.onSelect({ item: selectedItem });
}
}
};
}
<!doctype html>
<html ng-app="typeahead.demo">
<head>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.6.1/angular.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.6.1/angular-animate.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.6.1/angular-sanitize.js"></script>
<script src="//angular-ui.github.io/bootstrap/ui-bootstrap-tpls-2.5.0.js"></script>
<link href="//netdna.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
</head>
<script type="text/ng-template" id="typeahead-search-results.html">
<ul ng-init="$parent.$parent.initializeScope(this)"
class="dropdown-menu"
ng-show="isOpen() && !moveInProgress"
ng-style="{ top: position().top + 'px', left: position().left + 'px' }"
role="listbox"
aria-hidden="{{ !isOpen() }}">
<li class="uib-typeahead-match"
ng-repeat="match in matches track by $index"
ng-class="{ active: isActive($index) }"
ng-mouseenter="selectActive($index)"
ng-click="selectMatch($index, $event)"
role="option"
id="{{ ::match.id }}">
<div uib-typeahead-match
index="$index"
match="match"
query="query"
template-url="templateUrl"></div>
</li>
</ul>
</script>
<script type="text/ng-template" id="multi-select-typeahead.html">
<input type="text"
placeholder="{{::inputPlaceholder}}"
ng-model="searchTerm"
ng-model-options="{debounce: 500}"
uib-typeahead="result as result[displayNameField] for result in searchApi({ searchText: $viewValue })"
typeahead-is-open="isOpen"
class="form-control"
typeahead-popup-template-url="typeahead-search-results.html" />
</script>
<body>
<div ng-controller="TypeaheadDemo" style="padding-top: 15px;">
<multi-select-typeahead class="col-xs-6"
search-api="itemApi(searchText)"
display-name-field="name"
on-select="addItem(item)"
input-placeholder="Search Items...">
</multi-select-typeahead>
<div class="col-xs-6">
<ul class="list-group">
<li class="list-group-item" ng-repeat="item in items">
{{ item.name }}
</li>
</ul>
</div>
</div>
</body>
</html>

ngResource resourceProvider error with rails

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

Change position of input filed for jQuery Mobile Filter List

Im using the jQuery Mobile Filter List:
http://jquerymobile.com/test/docs/lists/lists-search-with-dividers.html
Is it possible to move the position of the input field so I can put it into a div already on my page?
Using jQuery's appendTo seems to work fine but its kind of a hacky solution. Thanks
this is what I found while searching for solution to a similar problem.
HTML code example:
<div data-role="page" id="page-id">
<div data-role="content">
<div data-role="fieldcontain">
<input type="search" name="password" id="search" value="" />
</div>
<div class="filter-div" data-filter="one">1</div>
<div class="filter-div" data-filter="two">2</div>
<div class="filter-div" data-filter="three">3</div>
<div class="filter-div" data-filter="four">4</div>
<div class="filter-div" data-filter="five">5</div>
</div>
</div>
JS code example:
$(document).delegate('#page-id', 'pageinit', function () {
var $filterDivs = $('.filter-div');
$('#search').bind('keyup change', function () {
if (this.value == '') {
$filterDivs.slideDown(500);
} else {
var regxp = new RegExp(this.value),
$show = $filterDivs.filter(function () {
return ($(this).attr('data-filter').search(regxp) > -1);
});
$filterDivs.not($show).slideUp(500);
$show.slideDown(500);
}
});
});
This way you can place your input text box anywhere on your page and it should properly filter a list of items you want.
JSFiddle DEMO: http://jsfiddle.net/cZW5r/30/

Resources