Argument 'Controller' is not defined - ruby-on-rails

I am making a little rails/angular project where I am trying to return a list of data from Instagram. Rails is just acting to serve files, and then will be deployed to heroku. The rest of the app is angular.
I keep getting the error
Argument 'MainController' is not a function, got undefined
So I know it has something to do with my controller. I have done a couple angular projects before and have them working, and I repeated my steps with this, but this error is driving me crazy and I cannot seem to figure out why it keeps coming up as my controller being undefined.
Here is my code;
app.js
var app = angular.module("hipstagram", ['ngResource']);
assets/javascripts/angular/services/main.js
app.factory('instagram', function($resource){
return {
fetchPopular: function(callback){
var api = $resource('https://api.instagram.com/v1/media/popular?client_id=:client_id&callback=JSON_CALLBACK',{
client_id: 'MY_CLIENT_ID'
},{
fetch:{method:'JSONP'}
});
api.fetch(function(response){
callback(response.data);
});
}
}
});
assets/javascripts/angular/controllers/main_ctrl.js
function MainController($scope, instagram){
$scope.layout = 'grid';
$scope.pics = [];
instagram.fetchPopular(function(data){
$scope.pics = data;
});
});
index.html.erb
<div ng-app="hipstagram" ng-controller="MainController">
<div class="bar">
</div>
<ul ng-show="layout == 'grid'" class="grid">
<!-- A view with big photos and no text -->
<li ng-repeat="p in pics">
<img ng-src="{{p.images.low_resolution.url}}" />
</li>
</ul>
<ul ng-show="layout == 'list'" class="list">
<!-- A compact view smaller photos and titles -->
<li ng-repeat="p in pics">
<img ng-src="{{p.images.thumbnail.url}}" />
<p>{{p.caption.text}}</p>
</li>
</ul>
</div>
From my troubleshooting, maybe angular is unable to access main controller, or I just named it wrong. If that is the case, any tips on how to get passed this would be great, I am stumped. Thanks for the help.

var app = angular.module("hipstagram", ['ngResource']);
app.controller("MainController", ["$scope", "instagram" ,function($scope, instagram){
$scope.layout = 'grid';
$scope.pics = [];
instagram.fetchPopular(function(data){
$scope.pics = data;
});
}]);

Instead of defining a global MainController function, do something like this:
app.controller('MainController', function ($scope, instagram){
$scope.layout = 'grid';
$scope.pics = [];
instagram.fetchPopular(function(data){
$scope.pics = data;
});
});
That registers the controller with the angular app so it can be used and dependency injected.

Related

How to run Angular JS on after page load rendered html?

I'm developing asp.net mvc a project with angular js.
I'm working on tabs and install related partial view after click event.
I am sending with partial view html of the json to main page but angular codes doesn't work on the page
What can i do?
Sample Problem
html:
<div ng-app="MyAppS">
<div ng-controller="AnaTest">
<button id="btn1" ng-click="btn1Click()">click</button>
</div>
<div id="m_area">
</div>
<br />{{ 'Hello Angular' }}</div>
javascript:
var m_app = angular.module('MyAppS', []);
function AnaTest($scope) {
$scope.btn1Click = function () {
var runtimeBtn = angular.element("<button ng-click=\"btn2Click()\">Help Me! </button>");
$('#m_area').html(runtimeBtn);
};
$scope.btn2Click = function(){
debugger;
alert('Why can not show?!');
};
};
m_app.controller('AnaTest', AnaTest);
You need to $compile it:
var runtimeBtn = $compile(angular.element("<button ng-click=\"btn2Click()\">Help Me!</button>"))($scope);
See it here: http://jsfiddle.net/7yqrjdkk/8/
However, a more "Angular" way to do it would be putting it under the same controller/scope and simply using ng-show, like this: http://jsfiddle.net/7yqrjdkk/9/

How to clear a new record from ember.js frontend after it fails Rails validation (422 error)?

I'm working on a basic reddit clone app with Rails and ember.js (via the ember-rails gem). Basically I have a 'post' model/controller in Rails which works correctly, but when I add a new post from the ember post model's create action, even if it fails the Rails validation, if I then go to the 'posts' index page which lists all the posts, I can see it there (i.e. ember is keeping the data). When I refresh it goes away, but I'm wondering what is the best way to purge that data so that it gets deleted upon rejection from the backend? Another odd thing is that simply going to the posts/new page at all creates a new blank post which is then visible on the Then on the client-side, I have the following files in app/assets/javascripts/routes:
posts_route.js:
RedditJp.PostsRoute = Ember.Route.extend({
model: function() {
return this.get('store').find('post');
}
});
posts_new_route.js:
RedditJp.PostsNewRoute = Ember.Route.extend({
model: function(){
return this.get('store').createRecord('post'); },
actions: {
create: function() {
var newPost = this.get('currentModel');
var self = this;
newPost.save().then(
function() { self.transitionTo('posts'); },
function() { }
);
}
}
});
Here's the form I'm trying to use to submit the data in posts/new.hbs:
<h1> Add a post </h1>
{{#each error in errors.title}}
<p>{{error.message}}</p>
{{/each}}
<form {{action "create" on="submit"}}>
<div>
<label>
Title<br/>
{{input type="text" value=title}}
</label>
</div>
<div>
<label>
Address<br/>
{{input type="text" value=address}}
</label>
</div>
<div>
<label>
Vote count<br/>
{{input type="text" value=voteCount}}
</label>
</div>
<button>Save</button>
</form>
and then in assets/javascripts/templates/posts/ I have index.hbs:
<h1>Posts</h1>
<ul>
{{#each}}
<li>{{title}} at {{address}} vote count: {{voteCount}}</li>
{{else}}
<li>There are no posts.</li>
{{/each}}
</ul>
and here's my router.js:
RedditJp.Router.map(function() {
this.resource('posts', function() {
this.route('new')
});
this.resource('home', function() {
});
});
RedditJp.IndexRoute = Ember.Route.extend({
redirect: function(){
this.transitionTo('home')
}
});
I was thinking I could just add a check in the posts/index.hbs file and only show records that aren't dirty, but there must be a cleaner way of doing it, so I'm wondering what would be considered best practice in this case (I'm thinking there should be some code I could add to the promise in posts_new_route.js to deal with this, but I can't quite figure it out).
Thanks a lot! And let me know if you need any additional info.
You can check if model isNew in template to hide new Record ( also you can use isEmpty property )
var record = store.createRecord('model');
record.get('isNew'); // true
record.save().then(function(model) {
model.get('isNew'); // false
});
In template will look like {{each model}}
{{#if model.get('isNew')}}
record.save().then(function(){
// Success callback
}, function() {
model..deleteRecord();
});

angularJS with MVC call - how to do something other than CRUD?

I've been following web tutorials to try to learn angularJS on a .NET MVC Application. All the tutorials seem to cover getting a list, getting an individual item etc.
What I want to do is allow the user to fill in an email address, I want to verify that email address against the database and return true or false if it existed. I'm then trying to put that value in the scope so I can do something in response to whether its true or false.
I'm using a single page app so this is the login html.
<form name="form" class="form-horizontal">
<div class="control-group" ng-class="{error: form.ValidEmailAddress.$invalid}">
<label class="control-label" for="ValidEmailAddress">Valid Email Address</label>
<div class="controls">
<input type="email" ng-model="item.ValidEmailAddress" id="ValidEmailAddress">
</div>
</div>
<div class="form-actions">
<button ng-click="login()" class="btn btn-primary">
Go!
</button>
<label ng-if="user.isAuthorised">Authorised</label>
<label ng-if="!user.isAuthorised">NotAuthorised</label>
</div>
</form>
In my app.js file I declare a loginCtrl controller when the url was /login so that's all fine. The logic that I'm calling on my button click is this:
var LoginCtrl = function ($scope, $location, $http, AuthorisedUser) {
$scope.login = function() {
var isValidUser = $http.get("/AuthorisedUser/IsValidUser/" + $scope.item.ValidEmailAddress);
$scope.user.isAuthorised = isValidUser;
} };
Which is then calling an MVC AuthorisedUserController class method:
public bool IsValidUser(string id)
{
var list = ((IObjectContextAdapter)db).ObjectContext.CreateObjectSet<ApprovedUser>();
var anyItems = list.Any(u => u.ValidEmailAddress == id);
return anyItems;
}
So it vaguely seemed to be working when I put in a value like "aaa" into the textbox. But as soon I try putting in an email address the value is undefined. Maybe I'm supposed to be doing a post but the only thing I can successfully hit my .NET controller with is by using get.
I'm sure I'm missing fundamental knowledge and potentially tackling this in the wrong way.
In case it helps I've created a module and defined factories like this:
var EventsCalendarApp = angular.module("EventsCalendarApp", ["ngRoute", "ngResource"]).
config(function ($routeProvider) {
$routeProvider.
when('/login', { controller: LoginCtrl, templateUrl: 'login.html', login: true }).
otherwise({ redirectTo: '/' });
});
EventsCalendarApp.factory('AuthorisedUser', function ($resource) {
return $resource('/api/AuthorisedUser/:id', { id: '#id' }, { isValidUser: { method: 'GET' } });
});
One of my questions is - should I be accessing the controller method using the $http object, or is there a way of using my factory declaration so that I can go something like:
AuthorisedUser.IsValidUser($scope.item.validEmailAddress)
I know in the tutorial I was following I could do stuff like:
CalendarEvent.save()
to be able to call a CalendarEventController post method.
What i think is, your get() function will return a promise. and you can't assign promise like this. so better try this approch once. I hope, it'd work. if not please let me know...
here I assume your first,second and third snippet of code works fine...
$http.get("/AuthorisedUser/IsValidUser/" + $scope.item.ValidEmailAddress).success(function (result, status) {
var isValidUser=result;
$scope.user.isAuthorised = isValidUser;
$scope.$apply();
}).error(function (result, status) {
//put some error msg
});

Cannot get jqueryui tabs to work properly in Ember view

I'm trying to run up a little prototype in Ember.JS at the moment with a view to completely re-writing the UI of a web application as an Ember Application running against a WebAPI, but although I've managed to get Ember running OK, I cannot get jqueryui to initialise the tabs correctly.
It seems to work fine if within the view I put static data for tabs to be created from, but if I'm using dynamic data then it just doesn't work.
I have an Ember view template
<script type="text/x-handlebars" id="index">
<div id="tabs" class="ui-tabs">
<ul>
{{#each model}}
<li>
<span class="ui-icon ui-icon-person"></span>
<a {{bindAttr href="route"}} {{bindAttr title="tabTitle"}}><span>{{title}}</span></a>
</li>
{{/each}}
</ul>
{{#each model}}
<div {{bindAttr id="tabTitle"}}>
<p>
Retrieving Data - {{title}}
</p>
</div>
{{/each}}
</div>
</script>
and a view
App.IndexView = Ember.View.extend({
templateName: 'index',
didInsertElement: function () {
var tabs = $("#tabs").tabs();
}
});
and a model
App.Section = DS.Model.extend({
name: DS.attr('string'),
title: DS.attr('string'),
tabTitle: function () {
return 'tab-' + this.get('name');
}.property("name"),
route: function () {
return '#' + this.get('tabTitle');
}.property("tabTitle")
});
App.Section.FIXTURES = [
{
id: 1,
name: 'home',
title: 'Home'
},
{
id: 2,
name: 'users',
title: 'Users'
}
];
It appears to generate the HTML correctly (from checking in Firebug), but this does not work, where as if I replace the template with
<script type="text/x-handlebars" id="index">
<div id="tabs" class="ui-tabs">
<ul>
<li>
<span class="ui-icon ui-icon-person"></span>
<span>Home</span>
</li>
<li>
<span class="ui-icon ui-icon-person"></span>
<span>Users</span>
</li>
</ul>
<div id="tab-home">
<p>
Retrieving Data - Home
</p>
</div>
<div id="tab-users">
<p>
Retrieving Data - Users
</p>
</div>
</div>
</script>
it works perfectly.
I'm assuming that it's something to do with the DOM not being completely rendered by the time the tabs are initialised, but everything I can find says that didInsertElement is the place to do it, and I have had time to dig deeper yet.
I'd be grateful for any ideas.
Edit: I've managed to make this work in a fashion by doing the following:
App.IndexView = Ember.View.extend({
templateName: 'index',
didInsertElement: function () {
Ember.run.next(this, function () {
if (this.$('#tab-users').length > 0) {
var tabs = $('#tabs').tabs();
} else {
Ember.run.next(this.didInsertElement);
}
});
},
});
The problem with this is that 1) it requires me to know what one of the last elements that will be written to the view is called (and obviously with dynamic data I won't necessarily know that), so that I can keep checking for it, and 2) the inefficiency of this technique makes me want to scream!
In addition, we get a good old FoUC (Flash of Unstyled Content) after things have been rendered, but before we then get JQueryUI to style them correctly.
Any suggestions gratefully received.
It's still not nice... but this at least does work, and is reasonably efficient...
From Ember.js - Using a Handlebars helper to detect that a subview has rendered I discovered how to write a trigger, and because of the way that the run loop seems to work, inserting the trigger in the last loop on the page causes it to be called n times, but only after the loop is complete, so a quick state check "hasBeenTriggered" ensures that you only execute the delgate function once.
My code now looks like this:
<script type="text/x-handlebars" id="index">
<div id="tabs" class="ui-tabs">
<ul>
{{#each model}}
<li>
<span class="ui-icon ui-icon-person"></span>
<a {{bindAttr href="route"}} {{bindAttr title="tabTitle"}}><span>{{title}}</span></a>
</li>
{{/each}}
</ul>
{{#each model}}
<div {{bindAttr id="tabTitle"}}>
<p>
Retrieving Data - {{title}}
</p>
</div>
{{trigger "triggered"}}
{{/each}}
</div>
</script>
with the trigger
Ember.Handlebars.registerHelper('trigger', function (evtName, options) {
options = arguments[arguments.length - 1];
var hash = options.hash,
view = options.data.view,
target;
view = view.get('concreteView');
if (hash.target) {
target = Ember.Handlebars.get(this, hash.target, options);
} else {
target = view;
}
Ember.run.next(function () {
target.trigger(evtName);
});
});
and view
App.IndexView = Ember.View.extend({
templateName: 'index',
hasBeenTriggered: false,
triggered: function () {
if (!this.get("hasBeenTriggered")) {
var tabs = $('#tabs').tabs();
this.set("hasBeenTriggered", true);
}
}
});
I'd love to know if there's a better way of doing this, as this still doesn't get round the FOUC problem either (which again can be done with more JS hacks)... :(

Expressions are not evaluated in $watch of custom directive of angularjs

I have a below custom directive in angularjs which uses model thats gets updated from server,
I have added a watch listener to watch the changes of that model,
var linkFn;
linkFn = function(scope, element, attrs) {
scope.$watch('$parent.photogallery', function(newValue, oldValue) {
if(angular.isUndefined(newValue)) {
return;
}
var $container = element;
alert($container.element);
$container.imagesLoaded(function() {
$container.masonry({
itemSelector : '.box'
});
});
});
};
return {
templateUrl:'templates/Photos_Masonry.htm',
replace: false,
transclude:true,
scope: {
photogallery: '=photoGallery',
},
restrict: 'A',
link: linkFn
However, when i debug in my watch directive, i still see that expressions in templates are still unresolved.i.e. photo.label, ng-src all are still unresolved. AFIK, $digest would be called only after $eval. Is this intended behavior?
My jQuery calls are not working due to this? Is there any other event where i get the result element with evaluated expressions?
Here is my template, which has ng-repeat in it,
<div id="container" class="clearfix">
<div class="box col2" ng-repeat="photo in photogallery">
<a ng-href="#/viewphotos?id={{photo.uniqueid}}&&galleryid={{galleryid}}"
title="{{photo.label}}"><img
ng-src="{{photo.thumbnail_url}}" alt="Stanley" class="fade_spot" /></a>
<h3>
<span style="border-bottom: 1px solid black;font-weight:normal;font-size:14px;">{{galleryname}}</span>
</h3>
<h3>
<span style="color:#20ACB8;font-weight:normal;font-size:17px;">{{photo.seasonname}}</span>
</h3>
</div>
</div>
photogallery is initialized in parent controller,
function MyCtrlCampaign($scope, srvgallery, mygallery) {
$scope.updatedata = function() {
$scope.photogallery = srvgallery.getphotos($routeParams);
};
$scope.getphotos = function() {
srvgallery.photos().success(function(data) {
$scope.updatedata();
}).error(function(data) {
});
};
Directive is used in below way,
<div masonry photo-gallery="photogallery" >
</div>
Kindly let me know your views on this.
Looks like this has been resolved in your Github issue (posted for the convenience of others).

Resources