我正在做一个最初的“学习”Ember 项目,该项目最终将演变成一个由 REST JSON 服务支持的完整应用程序。现在,我只是尝试创建一个简单的 CRUD 样式的页面集来管理公司列表。现在它使用 LocalStorage 直到它工作,然后我打算附加一个 REST 适配器。
在这三天里敲了我的脑袋后,我要来 SO 寻求帮助,拜托。
下面包含的代码(便于共享的单一 HTML 页面样式)似乎适用于使用 LocalStorage 适配器和 Fixture 适配器列出、添加和删除公司记录。不过,我有两个问题,其中一个正在杀死我。
当我单击公司详细信息页面中的“更新公司”按钮(路径 /companies/:company_id、控制器 App.CompaniesEditController、路由 App.CompaniesEditRoute)时,它给了我一个错误“未捕获的类型错误:无法调用未定义的方法“查找” “我不知道它是从哪里来的,也不知道为什么它没有保存。它似乎也是异步进入的。最终的“transitionToRoute”也没有被执行。我想我在路由器、控制器或模型(甚至可能是模板)上设置了不正确的东西,但我无法弄清楚。这是更紧迫的问题,拜托。
(低优先级)当数据(公司名称)在公司详情页面被编辑,但没有保存时,显然它仍在更新应用程序中存储的数据(即Javascript状态,而不是持久状态)。因此,如果我在该编辑页面上将公司名称从“abc”编辑为“def”,然后只需返回公司列表,该名称就会在公司列表中更新。但是,如果我重新加载页面(强制从本地存储重新加载数据),数据就会恢复。如果没有按下“保存”按钮,我怎样才能制作一个不会改变任何内容的查看/编辑页面?
谢谢阅读。完整代码如下。
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0">
<!-- See also: http://stackoverflow.com/questions/13588523/setting-page-title-with-ember-js -->
<title>Company Test</title>
<script src="handlebars-1.0.0.js"></script>
<script src="jquery-1.10.2.js"></script>
<!-- <script src="jquery-2.0.3.js"></script> -->
<script src="ember-1.0.0.js"></script>
<script src="ember-data-1.0.0-beta.2.js"></script>
<!-- Local storage adapter from: https://github.com/rpflorence/ember-localstorage-adapter -->
<script src="localstorage_adapter-20130906.js"></script>
<script>
// App is the name of our ember application in JavaScript
App = Ember.Application.create( { LOG_TRANSITIONS: true } );
// Our application's route map.
App.Router.map(function() {
this.resource('companies', { path: "/companies" }, function() {
// This page has three versions, a list, a new company and edit an existing company.
// The rendering goes through "companies" which should have an outlet for these
// two sub-pages and the main page (companies/index).
this.route('new', { path: "/new" });
this.route('edit', { path: "/:company_id" });
});
});
///////////////////////////////////////////////////////////////////////////////////////
// ROUTES
App.CompaniesRoute = Ember.Route.extend({
// Tell what data is available to this route
model: function() {
return this.store.find('company');
}
});
App.CompaniesIndexRoute = Ember.Route.extend({
model: function() {
// Reuse the parent route's model: http://stackoverflow.com/questions/14609757/emberjs-1-0-0pre4-how-do-you-pass-a-context-object-to-a-resource-index-rout/14610816#14610816
return this.modelFor('companies');
}
});
App.CompaniesEditRoute = Ember.Route.extend({
// This route's model has just the one specified company
model: function(co) {
console.log("Companies.Edit Route invoked with argument:");
console.log(co);
// This is company_id because that is what is specified in the route
var found = this.store.find('company', co.company_id);
console.log("Companies.Edit model is:");
console.log(found);
return found;
}
});
//////////////////////////////////////////////////////////////////////////////
// CONTROLLERS
// From the index (main) page of the companies list, you can
// add, edit and delete. Only delete has an action. The others
// just go to different routes.
App.CompaniesIndexController = Ember.ArrayController.extend({
actions: {
// Deletes the specified company
deleteCompany: function (co) {
co.deleteRecord();
co.save();
}
}
});
// The new page shows some empty fields and when add is selected,
// takes those and creates a new company from them. In the future,
// if there is an error saving, stay on the page and show a message.
// When added, clear the page for future use and go back to the
// company list. We might want to pass a message to say "added company
// so-and-so" at that point too.
App.CompaniesNewController = Ember.ArrayController.extend({
actions: {
createCompany: function () {
// Get value of name input box
var newName = this.get('name');
// Ignore blank companies
if (!newName.trim()) { return; }
// Create the new model entry
var newCo = this.store.createRecord('company', {
name: newName
});
// Clear name for next company to add
this.set('name', '');
// Save the new company to the model's backing store
newCo.save();
// And move to the list page
// TODO: Move this to the Router Events Hash (whatever that means)
this.transitionToRoute('companies');
}
}
});
// This page edits a company and saves it to the persistent store.
// TODO: How to make it not change the model object directly when
// the form is changed, but not saved?
App.CompaniesEditController = Ember.ObjectController.extend({
actions: {
updateCompany: function () {
// No idea why I can't save the company. Get this error:
// Uncaught TypeError: Cannot call method 'lookup' of undefined
/*
var content = this.get('content');
console.log("Content is:");
console.log(content);
console.log(content.data);
*/
var co = this.get('model');
console.log("Model is:");
console.log(co);
console.log(co.get('data'));
console.log("About to save...");
co.save();
console.log("Done with save...");
// Go back to the company list
this.transitionToRoute('companies');
}
}
});
//////////////////////////////////////////////////////////////////////
// EMBER DATA
// Set up Ember Data
// And Local Storage Adapter - https://github.com/rpflorence/ember-localstorage-adapter
App.Store = DS.Store.extend({
revision: 11, // Not sure what this means or is here for
adapter: DS.LSAdapter
});
// http://emberjs.com/guides/getting-started/using-other-adapters/
App.ApplicationAdapter = DS.LSAdapter.extend({
namespace: 'companies-demo'
});
// We're using the LocalStorage Adapter now, not Fixture Adapter
// App.ApplicationAdapter = DS.FixtureAdapter.extend();
//////////////////////////////////////////////////////////////////////////////////
// MODEL OBJECT TEMPLATES
App.Company = DS.Model.extend({
// I get an error if I use the below:
// Assertion failed: You may not set `id` as an attribute on your model. Please remove any lines that look like:
// `id: DS.attr('<type>')` from App.Company
//id: DS.attr('number'),
name: DS.attr('string')
});
// TEST DATA (When not using Local Storage Adapter)
App.Company.FIXTURES = [
{ id: 11, name: "Apple, Inc." },
{ id: 12, name: "Netflix, Inc." },
{ id: 13, name: "Facebook, Inc." },
{ id: 14, name: "Google, Inc." },
{ id: 15, name: "Microsoft, Inc." }
];
</script>
<!-- The main screen layout. It should be called "application". -->
<script type="text/x-handlebars" data-template-name='application'>
<header><font color="red">Shared page header</font></header>
<div>
{{outlet}}
</div>
<footer><font color="red">Copyright © Somewhen Somewho (shared page footer)</font></footer>
</script>
<!-- See this for how to set the page title (which I would like to do):
http://stackoverflow.com/questions/13588523/setting-page-title-with-ember-js -->
<!-- This page shows the log in or create account -->
<script type="text/x-handlebars" data-template-name='index'>
<p>{{#linkTo 'companies'}}View companies{{/linkTo}}</p>
</script>
<!-- This is an empty placeholder that will have the sub-pages
for index (the main company list), new and a single company
rendered into it. -->
<script type="text/x-handlebars" data-template-name='companies'>
{{outlet}}
</script>
<!-- This lists all companies and lets one be clicked to get the view/edit.
Future: Search box to show a list of companies with that in the name. -->
<script type="text/x-handlebars" data-template-name='companies/index'>
<h1>Company List</h1>
<p>{{#linkTo 'companies.new'}}Create a company{{/linkTo}}</p>
<ul>
{{#each}}
<li>
<label>{{#linkTo 'companies.edit' this}}{{name}}{{/linkTo}}</label>
<button {{action "deleteCompany" this}}>delete</button>
</li>
{{/each}}
</ul>
</script>
<!-- Shared content for both new/edit company -->
<script type="text/x-handlebars" data-template-name='_company-form'>
<p>{{#linkTo 'companies'}}Return to Company List{{/linkTo}}
<hr/>
<form>
<p>
{{#if id}}Company ID: {{id}}<br/>{{/if}}
Company Name: {{input type="text" id="new-name" placeholder="New Co." value=name}}
</p>
</form>
</script>
<!-- This views, adds or edits a company, depending on if the company has an ID or not
and whether the edit flag is set. VAE = VIEW ADD EDIT
Future: A DELETE button to delete a company and all its associated data (except
we don't actually delete it, we just mark it as deleted with a timestamp). -->
<script type="text/x-handlebars" data-template-name='companies/new'>
<h1>Add Company</h1>
{{partial "company-form"}}
<p><button {{action createCompany this}}>Add Company</button></p>
</script>
<script type="text/x-handlebars" data-template-name='companies/edit'>
<h1>Edit Company</h1>
{{partial "company-form"}}
<!-- FIXME: TODO: If you edit a company here and change its name, but
do NOT hit the "Update" button, it still shows the changed data
in the list and the edit page, but does NOT save it if you quit
the browser (or even reload the page). I wonder how we get it to restore the original data
if it is not saved? -->
<p><button {{action updateCompany this}}>Update Company</button></p>
</script>
</head>
<body bgcolor="#ffffff"></body>
</html>
<body bgcolor="#ffffff"></body>
</html>