How to fetch index data in Angular using rails server - ruby-on-rails

I am starting with Angularjs + rails backend and trying to fetch users data from the server - equivalent to to controller/index action in rails.
I have followed several tutorials and found this code as the most clear one....
questions
1. How to properly link angular module into views ?
2. How to fetch data using typeahead and sample data in this post.
here is plunker version of the code
Code is as follows:
views
<div ng-app='users'>
<div class='container-fluid' ng-controller="UsersIndexCtrl">
<pre>Model: {{result | json}}</pre>
<input type="text" ng-model="result" typeahead="suggestion for suggestion in users($viewValue)">
</div>
</div>
controller
<script>
// ['ui.bootstrap', 'ngResource'])
var app = angular.module('users', ['ui.bootstrap', 'ngResource']);
// factory - resources users
// equivalent to rails users/index
app.factory('Users', function($resource) {
return $resource('/users.json', {}, {
index: { method: 'GET', isArray: true}
});
});
// factory - user resource
// equivalent to users show, update
app.factory('User', function($resource) {
return $resource('/users/:user_id.json', {}, {
show: { method: 'GET' },
update: { method: 'PUT' }
});
});
// controller - users/ index
// equivalent to rails controller rails/index
var UsersIndexCtrl = function($scope, users) {
$scope.users = users;
};
</script>
and I am stack here, as I am getting this error:
Error: Unknown provider: usersProvider <- users
The goal of this code is to use typehead and provide data to the user.
My '/users.json' url is as follows:
[{"full_name":"Lia Cartwright","id":1,"image_url":"no-icon.jpg"},{"full_name":"Hilton Turner","id":2,"image_url":"no-icon.jpg"},{"full_name":"Aubrey Barrows","id":3,"image_url":"no-icon.jpg"},{"full_name":"Donnie Kris","id":4,"image_url":"no-icon.jpg"},{"full_name":"Eryn Rath","id":5,"image_url":"no-icon.jpg"},{"full_name":"Caden Fay","id":6,"image_url":"no-icon.jpg"},{"full_name":"Arlie Tromp","id":7,"image_url":"no-icon.jpg"},{"full_name":"Rico Klein","id":8,"image_url":"no-icon.jpg"},{"full_name":"Gudrun Dare","id":9,"image_url":"no-icon.jpg"},{"full_name":"Nathan Langworth","id":10,"image_url":"no-icon.jpg"},{"full_name":"Deanna Stroman","id":11,"image_url":"no-icon.jpg"},{"full_name":"Shania Stroman","id":12,"image_url":"no-icon.jpg"},{"full_name":"Lupe Harvey","id":13,"image_url":"no-icon.jpg"},{"full_name":"Constance Armstrong","id":14,"image_url":"no-icon.jpg"},{"full_name":"Reagan Tremblay","id":15,"image_url":"no-icon.jpg"},{"full_name":"Murray Sipes","id":16,"image_url":"no-icon.jpg"},{"full_name":"Dandre Klocko","id":17,"image_url":"no-icon.jpg"},{"full_name":"Haylee Monahan","id":18,"image_url":"no-icon.jpg"},{"full_name":"Florence Harber","id":19,"image_url":"no-icon.jpg"},{"full_name":"Norberto Hoppe","id":20,"image_url":"no-icon.jpg"}]

You must inject Users not users, it's case sensitive.
Side notes:
No need to create two models, replace:
app.factory('Users', function($resource) {
return $resource('/users.json', {}, {
index: { method: 'GET', isArray: true}
});
});
app.factory('User', function($resource) {
return $resource('/users/:user_id.json', {}, {
show: { method: 'GET' },
update: { method: 'PUT' }
});
});
with:
app.factory('User', function($resource) {
return $resource("users/:id", { id: '#id' }, {
index: { method: 'GET', isArray: true, responseType: 'json' },
show: { method: 'GET', responseType: 'json' },
update: { method: 'PUT', responseType: 'json' }
});
})
Other thing, in your controller, do:
var UsersIndexCtrl = function($scope, User) {
$scope.users = User.index();
};
Last thing, consider using: Angular Rails resource

Related

Use a factory in AngularJS

When a button is clicked, I want to create a new User, and redirect the person to http://www.myapp.com/#/user/134.
The below code works, but am I using AngularJS factories correctly? It feels strange to have to define a 'createUser' function in my controller.
myApp.factory('User', ['$resource', function($resource) {
return $resource("/users/:id", { id: "#id" },
{
'create': { method: 'POST' },
'index': { method: 'GET', isArray: true },
'show': { method: 'GET', isArray: false },
'update': { method: 'PUT' },
'destroy': { method: 'DELETE' }
}
);
}]);
myApp.controller('splash', ['$scope', '$http', '$location', 'User', function($scope, $http, $location, User){
$scope.createUser = function(){
User.create(
{},
function(response){
$scope.user = response;
$location.path('/users/' + $scope.user.id);
},
function(){
console.log('error creating user');
});
}
}]);
Here is a view with a button for creating a new user:
<button ng-click="createUser()">Create User</button>

Ruby on Rails textfield to route or specific webpage or to show action rather than list

The website i am building is in ruby on rails and it is about agriculture equipments. I have build a regular search page with input text field which when used list all items containing keyword
What i am planning to do is to have a textfield with bootstrap autocomplete feature. The text field will show options depending on input and when a single option is selected, i need it route to the particular items detail page i.e. show page rather than listing the results.
I need help with how to route directly to an items show page using the textfield value.
How can i do that?
Further to the comments, it sounds like you'll be wanting to create some sort of livesearch functionality, which basically uses ajax to send requests on keyup to your backend (PHP, Rails, etc)
We've done something like this here (search at the top):
--
The way to make this work is 3 fold:
Specific ajax route
Javascript to handle keyup
Controller action to send response
I understand this is not exactly what you want, but hopefully it will point you in the right direction
Routes
#config/routes.rb
resources :controller do
collection do
get "search(/:query)" #-> domain.com/controler/search/your_query
end
end
Controller
#app/controllers/your_controller.rb
class YourController < ApplicationController
respond_to :json, :js, :html
def search
#response = Model.where value: params[:query]
respond_with #response
end
end
JS
#app/assets/javascripts/jquery.livesearch.js
// Author: Ryan Heath
// http://rpheath.com
(function($) {
$.searchbox = {}
$.extend(true, $.searchbox, {
settings: {
url: 'search',
param: 'search',
dom_id: '#livesearch',
minChars: 2,
loading_css: '#livesearch_loading',
del_id: '#livesearch_del'
},
loading: function() {
$($.searchbox.settings.loading_css).show()
},
idle: function() {
$($.searchbox.settings.loading_css).hide()
},
start: function() {
$.searchbox.loading()
$(document).trigger('before.searchbox')
},
stop: function() {
$.searchbox.idle()
$(document).trigger('after.searchbox')
},
kill: function() {
$($.searchbox.settings.dom_id).fadeOut(50)
$($.searchbox.settings.dom_id).html('')
$($.searchbox.settings.del_id).fadeOut(100)
},
reset: function() {
$($.searchbox.settings.dom_id).html('')
$($.searchbox.settings.dom_id).fadeOut(50)
$('#SearchSearch').val('')
$($.searchbox.settings.del_id).fadeOut(100)
},
process: function(terms) {
if(/\S/.test(terms)) {
$.ajax({
type: 'GET',
url: $.searchbox.settings.url,
data: {search: terms.trim()},
complete: function(data) {
$($.searchbox.settings.del_id).fadeIn(50)
$($.searchbox.settings.dom_id).html(data.responseText)
if (!$($.searchbox.settings.dom_id).is(':empty')) {
$($.searchbox.settings.dom_id).fadeIn(100)
}
$.searchbox.stop();
}
});
return false;
}else{
$.searchbox.kill();
}
}
});
$.fn.searchbox = function(config) {
var settings = $.extend(true, $.searchbox.settings, config || {})
$(document).trigger('init.searchbox')
$.searchbox.idle()
return this.each(function() {
var $input = $(this)
$input
.keyup(function() {
if ($input.val() != this.previousValue) {
if(/\S/.test($input.val().trim()) && $input.val().trim().length > $.searchbox.settings.minChars){
$.searchbox.start()
$.searchbox.process($input.val())
}else{
$.searchbox.kill()
}
this.previousValue = $input.val()
}
})
})
}
})(jQuery);
#app/assets/javascripts/application.js
//Livesearch
$(document).ready( function() {
var base_url = window.location.protocol + "//" + window.location.host;
$('#SearchSearch').searchbox({
url: base_url + '/search/',
param: 'search',
dom_id: '#livesearch',
loading_css: '#livesearch_loading'
})
});

How to use an angularjs resource for rails/RESTful routes?

I've got an angularjs app embedded in a rails app. I'm using the RESTful methods provided by rails for a resource named "Task." Here are the routes I'm dealing with:
GET /api/v1/tasks.json
POST /api/v1/tasks.json
GET /api/v1/tasks/:id.json
PUT /api/v1/tasks/:id.json
DELETE /api/v1/tasks/:id.json
I've got an angularjs-resource for the Task item where the GET for all of the tasks works fine. (Code is in coffee script)
App.factory "Task", ["$resource", "$cookies", ($resource, $cookies) ->
$resource "/api/v1/tasks:slash:type.json?api_token=:api_token",
api_token: $cookies.api_token
type: '#id'
,
all:
method: "GET"
isArray: true
create:
method: "POST"
update:
method: "PUT"
params:
slash: "/"
remove:
method: "DELETE"
]
As you can sort of see here, I'm trying to insert a slash for the PUT method to get the format /api/v1/tasks/:id.json. Unfortunately, angular puts this in as a %2f rather than a slash. I'm not particularly excited about the quality of this code, since added the slash parameter makes it less readable.
Here's my angularjs controller using this resource:
taskController = App.controller 'TasksController', ($rootScope, $scope, $http, $cookies, Task) ->
$scope.message = $cookies.api_token
$scope.tasks = Task.all()
$scope.selectedTask = null
$scope.editTask = (task) ->
$scope.selectedTask = task
$scope.editDescription = task.description
$rootScope.date = new Date(task.dueDate)
console.log($rootScope.dt)
$scope.taskModal = true
$scope.saveTask = ->
$scope.taskModal = false
$scope.selectedTask.$update()
# Task.update({taskID: $scope.selectedTask.id, task: $scope.selectedTask})
console.log 'Implement saving...'
$scope.tasks = Task.all()
$scope.cancelTask = ->
$scope.taskModal = false
$scope.taskModalOptions = {
dialogFade: true
}
taskController.$inject = ['$rootScope', '$scope', '$http', '$cookies', 'Task']
Basically, my question is does anyone have an example of how do reproduce the traditional rails/RESTful URL formats with an angularjs resource? I've looked at several StackOverflow questions and can't seem to find a good answer. Any help is appreciated.
Have a look at restangular, its specifically designed to make HTTP verb requests to any REST api simple & easy.
https://github.com/mgonto/restangular
I had the problem with this and the nesting of the JSON data. The following code seems to work for me:
contacts.factory('Contacts', ['$resource',
function($resource) {
function nestData(data, headersGetter) {
return JSON.stringify({
contact: data
});
};
return $resource('/api/v1/contacts/:id.json', {
id: '#id'
}, {
'index': {
method: 'GET',
isArray: true
},
'show': {
method: 'GET',
isArray: false
},
'create': {
method: 'POST',
transformRequest: nestData
},
'save': {
method: 'PUT',
transformRequest: nestData
},
'destroy': {
method: 'DELETE'
}
}); // Note the full endpoint address
}
]);
In my controller I'm able to use:
function createContact(data) {
Contacts.save({
name: data.name,
phone: data.phone
});
}
Please give it a try and let me know

Populating a Webgrid from an Ajax Call

I have a problem with populating a Webgrid from an Ajax call.
I have followed the example as showed in the following thread: mvc3 populating bind webgrid from ajax however, that did not yield any results.
When I run the website, I always get the message: "Error: undefined".
when debugging the code, I am quite sure that the problem lies in the fact that the return PartialView is the problem, as my data object in the ajax success method does not get filled with data.
Here are the examples of my code:
Ajax call:
$.fn.getCardResult = function (leerling, kaart) {
$.ajax({
type: "GET",
url: '#Url.Action("GetResults","Kaarten")',
data: { leerlingID: leerling, cardID: kaart },
cache: false,
success: function (data) {
console.log(data);
if (!data.ok) {
window.alert(' error : ' + data.message);
}
else {
$('#card').html(data);
}
}
});
}
Partial View call:
<div class="card-content" id="card">
#{
if(Model.Kaart != null && Model.Kaart.Count > 0)
{
#Html.Partial("_Kaarten")
}
else
{
#: Er zijn geen kaarten beschikbaar.
}
}
</div>
Partial View:
#model List<ProjectCarrousel.Models.KaartenModel>
#{
var grid = new WebGrid(source: Model,ajaxUpdateContainerId: "card",
defaultSort: "Topicname");
grid.GetHtml(
tableStyle: "webgrid",
columns: grid.Columns(
grid.Column("Topicname", "Topic"),
grid.Column("Taskname", "Taken"),
grid.Column("Taskpoints", "Punten"),
grid.Column("Grades", "Resultaat"),
grid.Column("Date", "Datum"),
grid.Column("Teachercode", "Paraaf Docent")
)
);
}
Controller code:
public ActionResult GetResults(int leerlingID, string cardID)
{
try
{
int Ovnumber = leerlingID;
string CardId = cardID;
List<KaartenModel> kaartlijst = new List<KaartenModel>();
IEnumerable<topic> topics = _db.topic.Include("tasks.studenttotask").Where(i => i.CardID == CardId);
foreach (topic topic in topics)
{
foreach (tasks task in topic.tasks)
{
KaartenModel ka = new KaartenModel();
ka.Topicname = task.topic.Topicname;
ka.Taskname = task.Taskname;
ka.Taskpoints = task.Taskpoints;
ka.Ranks = task.Ranks;
ka.Date = task.studenttotask.Where(i => i.Ovnumber == Ovnumber).Select(d => d.Date).SingleOrDefault();
ka.Grades = task.studenttotask.Where(i => i.Ovnumber == Ovnumber).Select(d => d.Grades).SingleOrDefault();
ka.Teachercode = task.studenttotask.Where(i => i.Ovnumber == Ovnumber).Select(d => d.Teachercode).SingleOrDefault();
kaartlijst.Add(ka);
}
}
KVM.Kaart = kaartlijst;
return PartialView("_Kaarten", KVM.Kaart);
}
catch (Exception ex)
{
return Json(new { ok = false, message = ex.Message });
}
}
If anyone could help it would be greatly appreciated.
UPDATE
After fiddling about a bit I found a solution that worked for me. Below is a snippet of an updated Ajax Call:
The solution I found was too make the Success method in another way. This made sure that the Partial View rendered properly. Below is the Ajax call snippet.
$.ajax({
url: '#Url.Action("GetAjaxCall","Home")',
contentType: 'application/html; charset=utf-8',
type: 'GET',
dataType: 'html',
data: { id: id },
})
.success(function (result) {
$('#sectionContents').html(result);
})
.error(function (xhr, status) {
alert(xhr.responseText);
});
The solution I found was too make the Success method in another way. This made sure that the Partial View rendered properly. Below is the Ajax call snippet.
$.ajax({
url: '#Url.Action("GetAjaxCall","Home")',
contentType: 'application/html; charset=utf-8',
type: 'GET',
dataType: 'html',
data: { id: id },
})
.success(function (result) {
$('#sectionContents').html(result);
})
.error(function (xhr, status) {
alert(xhr.responseText);
});

show records in Angularjs - newbie

This is a real newbie question:
I have a view for my index in Rails in erb:
<div ng-app="Donor">
<div ng-controller="DonorCtrl">
<ul>
<li ng-repeat="donor in donors">
{{donor}}
</li>
</ul>
</div>
</div>
my Donor json returned from Rails is:
class DonorSerializer < ActiveModel::Serializer
attributes :id, :tools_id, :first_name, :last_name
end
My javascript file has this;
var app;
app = angular.module("Donor", ["ngResource"]);
// separate view to Add new donors
$scope.addDonor = function() {
var donor;
donor = Entry.save($scope.newDonor);
$scope.donors.push(entry);
return $scope.newDonor = {};
};
$scope.showDonors = function() {
var Donor = $resource("/donors", {
update: {
method: "GET"
}
});
return $scope.donors = Donor;
}
this.DonorCtrl = function($scope, $resource) {
var Donor;
Donor = $resource("/donors/:id", {
id: "#id"
}, {
update: {
method: "PUT"
}
});
return $scope.donors = Donor.query();
};
How do I get a list of donors to in my index view?
I am missing something
One of your first issues was that you did not have the right code inside of the controller. I also turned your $resource's into factory's. I changed the Donors update method to 'PUT' since you have an 'addDonor' method.
Make sure you also have the proper libraries setup for angularjs. For this you will need:
angular.js
angular-resource.js
The altered Javascript:
var app;
app = angular.module("Donor", ["ngResource"]);
app.factory("Donors", [
"$resource", function($resource) {
return $resource("/donors", {}, {
update: {
method: "PUT"
}
});
}
]);
app.factory("Donor", [
"$resource", function($resource) {
return $resource("/donors/:id", {
id: "#id"
}, {
update: {
method: "GET"
}
});
}
]);
this.DonorCtrl = [
"$scope", "Donor", "Donors", function($scope, Donor, Donors) {
var donor;
$scope.donor = Donor.query();
$scope.donors = Donors.query();
$scope.addDonor = function() {};
donor = Donor.save($scope.newDonor)(function() {
return $scope.donors.push(donor);
});
return $scope.newDonor = {};
}
];
Since you are using rails, here is the coffeescript version (I find it elegant in combination with angularjs):
app = angular.module("Donor", ["ngResource"])
app.factory "Donors", ["$resource", ($resource) ->
$resource("/donors", {}, {update: {method: "PUT"}})
]
app.factory "Donor", ["$resource", ($resource) ->
$resource("/donors/:id", {id: "#id"}, {update: {method: "GET"}})
]
#DonorCtrl = ["$scope", "Donor", "Donors", ($scope, Donor, Donors) ->
$scope.donor = Donor.query()
$scope.donors = Donors.query()
$scope.addDonor = ->
donor = Donor.save($scope.newDonor) ->
$scope.donors.push donor
$scope.newDonor = {}
]
I would checkout EggHead.io for a better understanding of how to setup your angular javascript files.

Resources