Ember local Variables in views - ruby-on-rails

So in Ember if I have a model called "foos" - it will load a template with the data-template-name="foos", however I am not sure how to wipe "foos" from the screen when I load 1 "foo" as well as I am not sure how to can the instance variable in the controller such as #foos to do a #foos.length. for some other stuff I want to do.
Currently my view doesn't load if I call foos.isLoaded as well as if I call foo #4 It will appendTo the page the view. but not redraw the view.
I just don't know how to figure out what the default stuff looks like I guess.
My controller stuff-
Router
App.Router.map(function(){
this.resource('records', function(){
this.resource('record', {path: ':record_id'});
});
});
App.FoosRoute = Ember.Route.extend({
model: function() {
return App.Foo.find();
}
});
// Controller
App.FoosController = Ember.ArrayController.extend({
itemController: 'record'
});
App.FooController = Ember.ObjectController.extend({
fullName: function() {
return this.get('firstName') + ' ' + this.get('middleName') + ' ' + this.get('surname') + ' ' + this.get('suffix')
}.property('firstName', 'middleName', 'surname', 'suffix')
})
// Model
App.Store = DS.Store.extend({
revision: 11,
adapter: 'DS.RESTAdapter'
});
App.Foo = DS.Model.extend({
firstName: DS.attr('string'),
middleName: DS.attr('string')
.....
})
My views:
<script type="text/x-handlebars" data-template-name="application">
{{ outlet }}
</script>
<script type="text/x-handlebars" data-template-name="foos">
<div class="one_half">
<h2>Search</h2>
form here....
</div>
<div class="one_half">
<div id="smallMap">
map
</div>
</div>
<div id="foos">
<table>
<tr>
<th>Name</th>
<th>Birth</th>
<th>Death</th>
</tr>
{{#each foo in controller}}
{{#if foo.isLoaded}}
<tr>
<td>{{#linkTo "foo" foo}} {{foo.fullName}} {{/linkTo}}</td>
<td>{{#linkTo "foo" foo}} {{foo.birthMonth}} {{#if foo.birthMonth}}/{{/if}}{{foo.birthDay}} {{#if foo.birthDay}}/{{/if}}{{foo.birthYear}} {{/linkTo}}</td>
<td>{{#linkTo "foo" foo}}{{foo.deathMonth}}{{#if foo.deathMonth}}/{{/if}}{{foo.deathDay}}{{#if foo.deathDay}}/{{/if}}{{foo.deathYear}}{{/linkTo}} {{foo.trAlt}}</td>
</tr>
{{else}}
<tr>
<td colspan="3" class="loading">Records are loading</td>
</tr>
{{/if}}
{{/each}}
</table>
</div>
{{outlet}}
</script>
<script type="text/x-handlebars" data-template-name="foo">
<h3>A Record</h3>
{{id}}
{{firstName}}
</script>
Currently it doesn't kill the view and bring in the new ones.

Hmmm - there is a lot going on here, going to try and point you in the right direction.
So in Ember if I have a model called "foos" - it will load a template with the data-template-name="foos"
Not exactly. Convention is to use the same name, but the ember does not load a template based on the model. If anything it's the other way around. Your best bet is usually to start with templates then work your way backwards to the model layer. So in this case let's start with 3 templates - application, foo and foos:
<script type="text/x-handlebars" data-template-name="application">
<h1>Foo App</h1>
{{outlet}}
</script>
<script type="text/x-handlebars" data-template-name="foos">
<h3>All Foos:</h3>
<ul>
{{#each controller}}<li>{{fullName}}</li>{{/each}}
</ul>
</script>
<script type="text/x-handlebars" data-template-name="foo">
<h3>Foo Details:</h3>
<p>{{fullName}}</p>
</script>
however I am not sure how to wipe "foos" from the screen when I load 1 "foo"
Ember will take care of rendering the appropriate view when the route changes. One way to make this possible is by adding links to your application. For example, modify foos template so that each record is a link, and add a Show All link to the detail page.
<script type="text/x-handlebars" data-template-name="foos">
<h3>All Foos:</h3>
<ul>
{{#each controller}}
<li>{{#linkTo "foo" this}}{{fullName}}{{/linkTo}}</li>
{{/each}}
</ul>
</script>
<script type="text/x-handlebars" data-template-name="foo">
<h3>Foo Details:</h3>
<p>{{fullName}}</p>
<p>{{#linkTo foos}}Show all{{/linkTo}}</p>
</script>
as well as I am not sure how to can the instance variable in the controller such as #foos to do a #foos.length for some other stuff I want to do
Not sure what your getting at. #foos is not an instance variable, unless you are using coffeescript and really mean this.foos.
Currently my view doesn't load if I call foos.isLoaded as well as if I call foo #4 It will appendTo the page the view. but not redraw the view.
Right. Calling foos.isLoaded just tells you if the model is loaded, it has nothing to do with the view. What do you mean call foo #4? Seems there might be code you are referencing that didn't get included in your SO post.
I just don't know how to figure out what the default stuff looks like I guess.
OK. I've made some guesses about what you're trying to do and created a working example. Code below, or see this working example on jsbin
First, I've added an application definition. Then changed your routes to be foos instead of records. Also no need for a nested route in this case.
App = Em.Application.create({});
App.Router.map(function(){
this.route('foos', {path: '/'});
this.resource('foo',{path: '/foos/:foo_id'});
});
FooRoute, FoosController and FooController were ok as-is.
App.FoosRoute = Ember.Route.extend({
model: function() {
return App.Foo.find();
}
});
// Controller
App.FoosController = Ember.ArrayController.extend({
itemController: 'foo'
});
App.FooController = Ember.ObjectController.extend({
fullName: function() {
return this.get('firstName') + ' ' + this.get('middleName') + ' ' + this.get('surname') + ' ' + this.get('suffix');
}.property('firstName', 'middleName', 'surname', 'suffix')
});
Added missing properties to App.Foo
App.Foo = DS.Model.extend({
firstName: DS.attr('string'),
middleName: DS.attr('string'),
surname: DS.attr('string'),
suffix: DS.attr('string')
});
Switching to DS.FixtureAdapter and added 4 fixture records to simulate what might be returned by your API
App.Store = DS.Store.extend({
revision: 11,
adapter: DS.FixtureAdapter
});
App.Foo.FIXTURES = [
{id: 1, firstName: 'Michael', middleName: 'Paul'},
{id: 2, firstName: 'Jennifer', middleName: 'Lyn'},
{id: 3, firstName: 'Sophia', middleName: 'Marie'},
{id: 4, firstName: 'Greta', middleName: 'Fae'}
];

Related

knockout in mvc - simple example not working

I got knockout to work before in MVC, but unfortunately I lost the code, and need help figuring it out.
I am trying to simply put an html page in the ~/wwwsource/ folder of my MVC project, and in that page I would like to demo a simple knockout example.
(Eventually, I actually want to use knockout inside MVC Views, using knockout right alongside Razor if possible but first I just would at least like to get a simple working example going, and extend from there.
I tried the following, which worked in JSFiddle but not in Visual Studio:
<script src="lib/knockout/dist/knockout.debug.js" type="text/javascript">
// Here's my data model
var ViewModel = function (first, last) {
this.firstName = ko.observable(first);
this.lastName = ko.observable(last);
this.fullName = ko.pureComputed(function () {
// Knockout tracks dependencies automatically. It knows that fullName depends on firstName and lastName, because these get called when evaluating fullName.
return this.firstName() + " " + this.lastName();
}, this);
};
ko.applyBindings(new ViewModel("Planet", "Earth"));
</script>
<p>First name: <input data-bind="value: firstName" /></p>
<p>Last name: <input data-bind="value: lastName" /></p>
<h2>Hello, <span data-bind="text: fullName"> </span>!</h2>
You are calling the javascript before the html has been fully rendered. So when ko.applyBindingsis called the html as only partially loaded.
Easiest solution is to wrap the javascript in a document loaded callback using jQuery (which should exist because you're using knockout).
You also have some invalid script tag syntax. Need to close knockout script tag before starting a new one for the page.
<script src="lib/knockout/dist/knockout.debug.js" type="text/javascript">
</script>
<script type="text/javascript">
// Here's my data model
var ViewModel = function (first, last) {
this.firstName = ko.observable(first);
this.lastName = ko.observable(last);
this.fullName = ko.pureComputed(function () {
// Knockout tracks dependencies automatically. It knows that fullName depends on firstName and lastName, because these get called when evaluating fullName.
return this.firstName() + " " + this.lastName();
}, this);
};
$(document).ready(function(){
ko.applyBindings(new ViewModel("Planet", "Earth"));
})
</script>
<p>First name: <input data-bind="value: firstName" /></p>
<p>Last name: <input data-bind="value: lastName" /></p>
<h2>Hello, <span data-bind="text: fullName"> </span>!</h2>

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

Routing with angularjs in Mvc application

I have been continously trying to implement routing in Angularjs with Mvc 4.0 project but I am not able to do it.
I have created a empty MVC 4.0 project and added a controller "HomeController". Then I added a folder in Views with name Home having three views. One is index which opens when we run application as in route config we have route for homecontroller and Index Action.So, basically assuming the index page as the main page in Singlepage application, I have defined some code in the index page as given in 6oish book enter link description here.
Index. CShtml
#{
ViewBag.Title = "Index";
}
<style>
.container {
float: left;
width: 100%;
}
</style>
<script src="~/Scripts/angular.min.js"></script>
<h2>Practising Angular</h2>
List
Edit
<div ng-app="demoApp">
<div class="container">
<div ng-view=""></div>
</div>
</div>
<script>
var demoApp = angular.module('demoApp', []);
demoApp.config(function ($routeProvider) {
$routeProvider.when('/', { controller: 'SimpleController', templateUrl: 'Home/List' })
.when('/Edit', { controller: 'SimpleController', templateUrl: 'Home/Edit' })
.otherwise({ redirectTo: '/' });
});
demoApp.controller('SimpleController', function ($scope) {
$scope.customers = [{ name: 'Dave jones', city: 'Phoenix' },
{ name: 'Jhon Dena', city: 'Mexico' },
{ name: 'Bradshaw', city: 'WashingTon' },
{ name: 'Rey Mysterio', city: 'Brazil' },
{ name: 'Randy', city: 'California' }, ];
});
$scope.addCustomer = function () {
$scope.customers.push({ name: $scope.newCustomer.name, city: $scope.newCustomer.city })
};
</script>
Now, I need two more Views which are defined in the above route and they are as follows:
List.cshtml
#{
ViewBag.Title = "List";
}
<h2>Listing the users in order </h2>
<div class="container">
Name: <input type="text" ng-model="filter.name" />
<ul>
<li ng-repeat="objCust in customers | filter:filter.name">{{objCust.name }}-{{objCust.city}}
</li>
</ul>
Customer Name:<br />
<input type="text" ng-model="newCustomer.name" /><br />
Customer city:<br />
<input type="text" ng-model="newCustomer.city" /><br />
<button ng-click="addcustomer()">Add customer</button>
</div>
and Last one is
Edit.cshtml
#{
ViewBag.Title = "Edit";
}
<h2>Edit the particular user. Things are under construction</h2>
<h2>Listing the users in order </h2>
<div class="container">
Name: <input type="text" ng-model="city" />
<ul>
<li ng-repeat="objCust in customers | filter:city">{{objCust.name }}-{{objCust.city}}
</li>
</ul>
</div>
Here is the home controller
namespace Routing_Angular.Controllers
{
public class HomeController : Controller
{
//
// GET: /Home/
public ActionResult Index()
{
return View();
}
public ActionResult List()
{
return PartialView();
}
public ActionResult Edit()
{
return PartialView();
}
}
}
I am attaching a image to show the Project structure.
I ma running the application, I can see the empty page where it is written "Practising Angular" with two anchor tags "List" and "Edit". I am not getting any change on changing the url.I added "/" in the url and It is not changed . then I added a "/Edit". then also I found no change. I have added anchor tags at the top in index page then also there is no change. only url gets changed. Please guide me where I am doing wrong.
There are a few things you need to fix in your views and angular code.
First of all, when defining the SimpleController, you have defined the addCustomer function outside the controller.
You should have the following controller definition:
demoApp.controller('SimpleController', function ($scope) {
$scope.customers = [{ name: 'Dave jones', city: 'Phoenix' },
{ name: 'Jhon Dena', city: 'Mexico' },
{ name: 'Bradshaw', city: 'WashingTon' },
{ name: 'Rey Mysterio', city: 'Brazil' },
{ name: 'Randy', city: 'California' }, ];
$scope.addCustomer = function () {
$scope.customers.push({ name: $scope.newCustomer.name, city: $scope.newCustomer.city });
};
});
Then in your list view, the function declared for the "Add Customer" button is wrong, as it is case sensitive. You should have addCustomer instead of addcustomer (with capital C, as defined in your SimpleController):
<button ng-click="addCustomer()">Add customer</button>
Also, I am not sure which version of angular you are using, but from version 1.2.0, routing needs to be loaded as a separate module (see this error). You can install it following these instructions, adding the script angular-route.min.js and declaring your module as:
var demoApp = angular.module('demoApp', ['ngRoute']);
You will know that you need to load the routing module because you will see an exception in the browser console when the initial Index view loads. (It's always a good idea to check the browser console for JS errors anyway)
That should be everything, hope it helps!

add item to observable array in viewmodel from another partial view (MVC)

I am new to knockoutJS. I am working on an MVC application where I want to implement knockoutJS but the scenario is bit different.
I have a page where I am showing a list. I have 3 links on the page and on click of them I am adding partial views to page accordingly. What I want to do is that whenever I add values/data to partial views, the list which is on page should be updated with knockout. In other words I want to add value to observable array when I save data from partial view.
Please let me know if this is possible or I should keep it in jquery only.
Here is the code:
Main view:
<input type="button" value="Add Partial View" onclick="LoadPartial();" />
<div id="dvContent"></div>
<h4>People</h4>
<ul data-bind="foreach: people">
<li>
Name at position <span data-bind="text: $index"> </span>:
<span data-bind="text: name"> </span>
Remove
</li>
</ul>
<button data-bind="click: addPerson">Add</button>
<script src="~/Scripts/jquery-1.7.1.js"></script>
<script src="~/Scripts/knockout-2.1.0.js"></script>
<script>
function LoadPartial() {
$.ajax({
url: "/home/index",
dataType:"html",
type: "GET",
success: function (data) {
$("#dvContent").html(data);
}
});
}
</script>
<script>
function AppViewModel() {
var self = this;
self.people = ko.observableArray([
{ name: 'Bert' },
{ name: 'Charles' },
{ name: 'Denise' }
]);
self.addPerson = function () {
self.people.push({ name: "New at " + new Date() });
};
self.removePerson = function () {
self.people.remove(this);
}
}
ko.applyBindings(new AppViewModel());
</script>
Partial View:
<table>
<tr>
<td>Add new Row</td>
<td><input type="button" value="Add" data-bind="click: addPerson"/></td>
</tr>
</table>
Thanks,
JsHunjan
It is easy to accomplish with Knockout. You need to show some code that you have tried though if you want to get some help. I will post a general answer but it isn't going to fix your use case exactly, just basically -
Create an object to hold your new item, you can do this either in the parent or the child view model, but if you do it in the child you need to pass it back to the parent.
Once you hit a save button or add or whatever in the child view model just do a .push() into the observableArray that you created ex... - myObservableArray.push(newItem());
Knockout will recognize all of the changes taking place and perform the actions you want automatically.
Hope this helps.

Getting Results in Ember Views

So it has been a long couple of days to get all the Emberjs stuff to play nice together. I really like this journey, but from time to time am beginning to feel to old to do this.
So I have a app hits the /#/Records link. From their It needs to query Rails, return the results, and then grab the show view on the other pages.
When I had this as a single page app, with the views on the page, I had it working.... Now the last 2 days, confusion has crept in. (some extra bits in views and such are removed.
My hbs records/index view file which is partially showing up:
<table>
<tr>
<th>Name</th>
<tr>
<td colspan="3">{{counter}}</td>
</tr>
</tr>
{{#each record in controller}}
<tr>
<td>{{#linkTo "record" record}} {{record.fullName}} {{/linkTo}}</td>
</tr>
{{/each}}
</table>
My Ember App:
App = Ember.Application.create({
rootElement: '#ember'
});
App.RecordsController = Ember.ArrayController.extend({
});
App.Store = DS.Store.extend({
revision: 11,
adapter: 'DS.RESTAdapter'
});
App.Record = DS.Model.extend({
firstName: DS.attr('string'),
middleName: DS.attr('string'),
surname: DS.attr('string'),
suffix: DS.attr('string'),
})
App.Router.map(function(){
this.resource('records');
this.resource('record', {path: 'records/:record_id'})
});
App.IndexRoute = Ember.Route.extend({
redirect: function(){
this.transitionTo('records')
}
});
App.RecordsRoute = Ember.Route.extend({
});
Modify your records route to look like the below. This model hook provides you a way to specify how a controller will get it's content / model. Now when you view the network tab you should see an ajax request to fetch all the records from your backend (via ember-data)
App.RecordsRoute = Ember.Route.extend({
model: function() {
return App.Record.find();
}
});

Resources