I start of by calling a method in my MVC-app that returns a list of objects in
$scope.centrals:
var result = $http.get("/Home/GetCentraler");
result.success(function (data) {
$scope.centraler = data;
});
In my main-view I display the items like this:
<tr ng-repeat="product in centraler | orderBy:'name' | filter:search" >
<td class="tdCenter"><img ng-src="{{product.img}}" alt="{{product.name}}" /></td>
<td>
<b>{{product.namn}}</b><br />
{{product.description}}
</td>
</tr>
As you may see, when I click the product.name, I would like to display that item in a specific view.
I must be missing something, I guess I should make a new method in MVC that picks out the object containing the clicked Id. But how can I the pass this object into:
<a href="#/products/{{product.id}}"
My Routing is set up like this:
var storeApp = angular.module('MyAPp', ['ngRoute']).
config(['$routeProvider', function ($routeProvider) {
$routeProvider.
when('/store', {
templateUrl: '/Angular/partials/store.htm',
controller: storeController
}).
when('/products/:Id', {
templateUrl: '/Angular/partials/product.htm',
controller: storeController
}).
otherwise({
redirectTo: '/store'
});
}]);
EDIT1:
When I click the productname-link now, it goes to the correct view but nothing is brought to it.
EDIT2:
function storeController($scope, $routeParams, $http) {
var result = $http.get("/Home/GetCentraler");
result.success(function(data) {
$scope.centraler = data;
function activate() {
$scope.search = $routeParams;
if ($routeParams.Id) {
angular.forEach($scope.centraler, function(item) {
if (item.id == $routeParams.Id) {
$scope.item = item;
}
})
}
};
});
}
Please see that demo should helps you a bit http://plnkr.co/edit/XyWvKQLuQsegoyG19sg5?p=preview
I can't see definition for storeController in your code and should pass controller name as a string inside route configuration.
Other thing you should have rather different controller for product view and store view
.config(['$routeProvider',
function($routeProvider) {
$routeProvider.
when('/store', {
templateUrl: '/Angular/partials/store.htm',
controller: 'storeController'
}).
when('/products/:Id', {
templateUrl: '/Angular/partials/product.htm',
controller: 'storeController'
}).
otherwise({
redirectTo: '/store'
});
}
])
Related
I am trying to display json data which I am getting from my rails controller in my views. But I believe I am missing something while calling the service in my app controller.
**My service**
.service("articles", function($http){
var o = this;
o.getall = function(){
return $http.get('/articles.json').then(function(response){
console.log(response.data);
return response.data;
});
};
});
**My controller**
.controller('FirstCtrl', function($scope, articles, Data){
var first = this;
first.message = "Welcome!"
first.data = articles.getall();
});
**Angular route**
$stateProvider.state("first", {
url : "",
controller : "FirstCtrl as first",
templateUrl: "templates/first.html"
});
First.html
<h1> Angular-rails </h1>
<h2>{{first.message}}</h2>
<div ng-repeat="article in first.data">
<h2>{{article.title}}</h2>
<h2>{{article.description}}</h2>
</div>
return the promise from service to controller, like this
*My service**
.service("articles", function($http){
var o = this;
o.getall = function(){
return $http.get('/articles.json');
};
});
**My controller**
.controller('FirstCtrl', function($scope, articles, Data){
var first = this;
first.message = "Welcome!"
articles.getall().then(function(response){
console.log(response.data);
first.data = response.data;
});;
});
**Angular route**
$stateProvider.state("first", {
url : "",
controller : "FirstCtrl as first",
templateUrl: "templates/first.html"
});
First.html
<h1> Angular-rails </h1>
<h2>{{first.message}}</h2>
<div ng-repeat="article in first.data">
<h2>{{article.title}}</h2>
<h2>{{article.description}}</h2>
</div>
I have a bootstrap nav-tab and I want to display dynamically content when I select a tab. Each tab must display a div with some text that is returned from ajax call at the controller's action GetSection().
<div class="tabbable">
<ul class="nav nav-tabs" data-bind="foreach: sections">
<li data-bind="css: { active: isSelected }">
<a href="#" data-bind="click: $parent.selectedSection">
<span data-bind="text: name" />
</a>
</li>
</ul>
<div class="tab-content" data-bind="foreach: sections">
<div class="tab-pane" data-bind="css: { active: isSelected }">
<span data-bind="text: 'In section: ' + retValue" />
</div>
</div>
</div>
Javascript code:
var Section = function (name, selected) {
this.name = name;
this.retValue = "";
this.isSelected = ko.computed(function () {
return this === selected();
}, this);
}
var ViewModel = function () {
var self = this;
self.selectedSection = ko.observable();
self.sections = ko.observableArray([
new Section('Tab One', self.selectedSection),
new Section('Tab Two', self.selectedSection),
new Section('Tab Three', self.selectedSection)
]);
self.selectedSection(self.sections()[0]);
self.selectedSection.subscribe(function () {
$.ajax({
url: '#Url.Action("GetSection")',
data: { name: self.selectedSection().name },
type: 'GET',
success: function (data) {
self.selectedSection().retValue=data.text;
}
});
});
}
ko.applyBindings(new ViewModel());
The problem is that retValue from ajax is not displayed. The controller action is this:
public JsonResult GetSection(string name)
{
var ret = new { text = name + "abcd" };
return Json(ret, JsonRequestBehavior.AllowGet);
}
Knockout can only know to update the view for properties that are obsverable (hence the name), so you need to make retValue observable:
var Section = function (name, selected) {
this.name = name; // <-- consider similar change here too
this.retValue = ko.observable(""); // <-- change here
this.isSelected = ko.computed(function () {
return this === selected();
}, this);
}
Then, you need to remember to set an obsverable's value by calling it as a method with the new value as its only argument, e.g.:
$.ajax({
url: '#Url.Action("GetSection")',
data: { name: self.selectedSection().name },
type: 'GET',
success: function (data) {
self.selectedSection().retValue(data.text); // <-- change here
}
});
And finally, if you're binding to a complex expression in your view you need to invoke it as a function (with no arguments) to get its value:
<span data-bind="text: 'In section: ' + retValue()" />
As a side note, realize that you can leave off the parentheses (consider it syntactic sugar from knockout) if you bind straight to just the observable, e.g.:
<span data-bind="text: retValue" />
Which is effectively equivalent to:
<span data-bind="text: retValue()" />
On a foot note, I see you've used this syntax for a click binding:
...
This works... but only by coincidence. You should realize these things together:
$parent.selectedSection contains the result of ko.observable() which means it is in fact a function that can be invoked
the click data-binding will invoke the expression it gets as a function, passing the contextual data (in your case a Section) to that function
So bascially, when the click happens, this happens:
$parent.selectedSection($data) // where $data == the current Section
Which effectively selects the Section.
It would be more verbose though a lot clearer if the $parent had a function:
var self = this;
self.selectChild = function(section) {
// Possibly handle other things here too, e.g. clean-up of the old selected tab
self.selectedSection(section);
}
And then use the click binding in this clear way:
...
On click the selectChild method will be called, again with the contextual data as the argument.
Instead of this
self.selectedSection().retValue=data.text;
Do this
self.selectedSection(data);
I'm getting a WARNING: Tried to load angular more than once. when trying to use nested views on a Ruby on Rails and Angular app. I'm using ui-router and angular-rails-templates.
Angular config and controllers:
var app = angular.module('app', ['ui.router', 'templates']);
app.factory('categories', ['$http', function($http) {
var o = {
categories: []
};
o.get = function (id) {
return $http.get('/categories/' + id + '.json').then(function (res) {
return res.data;
});
};
return o;
}]);
app.config([
'$stateProvider',
'$urlRouterProvider',
function($stateProvider, $urlRouterProvider) {
$stateProvider
.state('home', {
url: '/home',
templateUrl: 'home/_home.html',
controller: 'MainCtrl',
});
$stateProvider
.state('home.categories', {
url: '/categories/:categoryId',
templateUrl: 'categories/_categories.html',
controller: 'CategoriesCtrl',
resolve: {
category: ['$stateParams', 'categories', function($stateParams, categories) {
return categories.get($stateParams.categoryId);
}]
}
});
$urlRouterProvider.otherwise('/home');
}]);
app.controller('MainCtrl', function ($state) {
$state.transitionTo('home.categories');
});
app.controller('CategoriesCtrl', [
'$scope',
'categories',
'category',
function($scope, categories, category) {
$scope.posts = category.posts;
}
]);
And the templates:
_home.html (*edited: deleted body and ng-app from this template, following #apneadiving advice, and used the right path, as pointed by #Pankaj Now, views are rendered properly, but the 'loading more than once' persists)
Category One
Category Two
<ui-view></ui-view>
_categories.html
<ul ng-repeat="post in posts">
<li>{{post.title}}</li>
</ul>
app/views/layouts/application.html.erb
<!--<rails head>-->
<body ng-app="app">
<ui-view></ui-view>
</body>
What is happening is that the state 'home' appears and when I click on the links, the URL changes but nothing else happens. And I get the message that Angular is being loaded more than once.
EDITED: Got it working. It was a <%= yield %> conflict in another part of the app that should have nothing to do with the Angular part.
As you are defined the child states, you need to change your URL's to /home as they are child of home state, the URL gets inherited from parent state.
Category One
Category Two
You shouldnt boot your app in a template like you do.
Add the ng-app to your html's body and remove it from the template (actually your template shouldnt bear the body either)
I made this small API on rails with a single resource called Items, that works fine while I use it on the browser (a.k.a http://localhost:9000/api/items/1.js - Configured port 9000 with Grunt proxy), but when I try to get that data from Angular I get nothing.
//app.js
.config(function ($routeProvider) {
$routeProvider
.when('/items', {
templateUrl: 'views/items.html',
controller: 'ItemsCtrl'
})
.otherwise({
redirectTo: '/'
});
});
app.factory('Item', ['$resource', function($resource) {
return $resource('http://localhost:9000/api/items/:id.json', null, {
'update': { method:'PUT' }
});
}]);
//items.js
angular.module('balenciagaApp')
.controller('ItemsCtrl', ['$scope', 'Item', function ($scope, Item) {
$scope.items = Item.query();
}]);
//items.html
<ul ng-repeat="item in items">
<li>{{item.name}}</li>
</ul>
Ok, I'm using ASP.NET MVC5 + AngularJS 1.3.8 here.
Index.vbhtml:
<div ng-controller="MainController">
<tabset justified="true">
<tab ng-repeat="t in tabs" heading="{{t.heading}}" select="go(t.route)" active="t.active"></tab>
</tabset>
</div>
<div ui-view="main"></div>
Tabs are working fine.
App.js:
App.config(function ($stateProvider, $urlRouterProvider, $locationProvider) {
//$locationProvider.html5Mode(true); // HTML5 Mode to remove hashbang, want to revist this later as it requires IIS rewrite rules
$urlRouterProvider.otherwise("/");
$stateProvider
// Main Page
.state('main', {
abstract: true,
url: '/',
views: {
'main': {
templateUrl: '/',
controller: 'MainController'
}
}
})
// Home page
.state('home', {
url: '/home',
views: {
'main': {
templateUrl: '/Home/Index',
controller: 'HomeController'
}
}
})
// Requests Page
.state('requests', {
url: '/requests',
views: {
'main': {
templateUrl: '/Request/Index',
controller: 'RequestController'
}
}
})
// Leave Requests page
.state('requests.leave', {
url: '/leave',
views: {
'main': {
templateUrl: '/Request/Leave',
controller: 'LeaveController'
}
}
})
App.controller('RequestController', function ($scope, $state) {
$scope.loadComp = function () {
$state.go('requests.comp');
};
$scope.loadOvertime = function () {
$state.go('requests.overtime');
};
$scope.loadLeave = function () {
$state.go('requests.leave');
};
});
Ok, so what I'm trying to accomplish is that on my Requests tab, I have three buttons, and when I click on one of those buttons, replace the parent view "main" with the appropriate state.
I see the URL change on the button click, but nothing renders.
I am getting my partial views back from the server via AJAX with no issues, except for these button clicks :(
I'd love to know what I'm doing wrong :) Thanks!
FWIW: Angular UI-Router: child using parent's view I've been trying to rework this with no luck...
What I would do is trying to point to the real templates in templateUrl like so: templateUrl: '/Request/Index.html'