I am trying to integrate FlowJS with EmberJS. I was successful to upload data to server, so, I am good on that part.
I am unsuccessful When trying to bind flow object data with emberJS component to show data via handlebars. For some reason data binding is not working.
Here is an example of the code.
HTML
<script type="text/x-handlebars" data-template-name="index">
{{flow-uploader}}
</script>
<script type="text/x-handlebars" id="components/flow-uploader">
<div class="drop"></div>
<!-- file list -->
{{#each file in flow.files}}
<p>File name: {{file.name}}</p>
{{/each}}
</script>
JS
App = Ember.Application.create({
rootElement: '#main'
});
App.FlowUploaderComponent = Ember.Component.extend({
flow: function(){
return new Flow({
target: 'http://google.com',
testChunks: false
});
}.property(),
initDropZone: function(){
var flow = this.get('flow');
var drop = this.$('.drop')[0];
var $this = this;
flow.assignDrop(drop);
/*flow.on('fileAdded', function(file, flow){
});
flow.on('filesAdded', function(files){
});
flow.on('fileSuccess', function(file,message){
console.log('file success');
});
flow.on('fileError', function(flow, message, chunk){
console.log('file error');
});*/
flow.on('filesSubmitted', function(){
console.log($this.get('flow').files);
//flow.upload();
});
/*flow.on('complete', function(event, flow){
console.log('completed');
});
flow.on('uploadStart', function(event, flow){
console.log('uploading..');
});
flow.on('fileProgress', function(flow, file){
});*/
}.on('didInsertElement')
});
Example can be seen live at http://jsfiddle.net/sisir/qLuobq48/2/
Basically what I am doing here is to save the flow object as component property. files property of flow object is the array of file to be uploaded. Once we drag and drop or select multiple files to upload the files array gets updated. We can see it on the console. The logging code is added via filesSubmitted event.
From the handlebars expression each file is iterated from the files queue. Initially it is empty but later when it gets populated it doesn't show on the html. The data binding is not working for some reason.
In your component logic:
App.FlowUploaderComponent = Ember.Component.extend({
flow: function(){
return new Flow({
target: 'http://google.com',
testChunks: false
});
}.property(),
initDropZone: function(){
var $this = this;
var flow = this.get('flow');
var drop = this.$('.drop')[0];
flow.assignDrop(drop);
flow.on('filesSubmitted', function(){
//for setting a single property
$this.set('flowFiles', flow.files);
//for setting multiple properties
// $this.setProperties({'flowFiles': flow.files, /* etc.. */});
});
}.on('didInsertElement')
});
In your template:
<script type="text/x-handlebars" data-template-name="index">
{{flow-uploader}}
</script>
<script type="text/x-handlebars" id="components/flow-uploader">
<div class="drop"></div>
<!-- file list -->
{{#each file in flowFiles}}
File name: {{file.name}}
{{/each}}
</script>
See JSBin Example
The problem with your JSFiddle simply is(/was) that you referenced a text/plain file as JavaScript. As I asked here, not every file is usable in JSFiddle and GitHub does not like to get misused as pseudo-CDN for lazy people.
In other words: This error
Uncaught ReferenceError: Flow is not defined
is a result of this error
Refused to execute script from 'https://raw.githubusercontent.com/flowjs/flow.js/master/dist/flow.min.js' because its MIME type ('text/plain') is not executable, and strict MIME type checking is enabled.
and can be fixed using
https://rawgithub.com
or the MaxCDN version
http://rawgit.com/
in place of the branch file URl.
Look at the new JSFiddle with all the console.log() statements. The files added, file added and submitted logs in the console are telling me that everything in your code works fine once you got the right file in use. PROTip: Always check your console for errors.
Related
Apologies if this isn't quite the right place (as opposed to either libraries own github issue page, but as I've not been able to determine exactly which library is not quite working correctly hard to log it specifically).
I'm using ember data fragments on my model (an array), and localstorage to save down my model. When calling rollback upon the saved model, it seems to reset the fragments back to their original state (i.e. no values), but it still maintains the fragment itself on the array, rather than dropping the item out of the array.
I've got a fiddle setup, click 'add' to add a model, click to view it's details, then click 'add' in there, followed by 'cancel'. You can see that the type + desc values drop out, but the element is still there.
If I switch out to using the Fixture adapter then it all works as expected, just not sure where to start even attempting to debug, I've stepped through many lines of _super calls, and what not trying to figure it out, but just get lost.
Note
This is a pseudo version of my actual app, and curiously enough when you navigate to the home page and then back to the details page, it seems to resolve the type/desc correctly, which it is not doing on my actual app, it still maintains the default values. However refreshing the page makes it work perfectly from then onwards.
Any help greatly appreciated!
<!DOCTYPE html>
<html>
<head>
<script src="//code.jquery.com/jquery-1.11.1.min.js"></script>
<script src="//builds.handlebarsjs.com.s3.amazonaws.com/handlebars-v1.3.0.js"></script>
<script src="//builds.emberjs.com/tags/v1.7.0/ember.js"></script>
<script src="//builds.emberjs.com/canary/ember-data.js"></script>
<script src="//raw.githubusercontent.com/lytics/ember-data.model-fragments/master/dist/ember-data.model-fragments.js"></script>
<script src="//raw.githubusercontent.com/kurko/ember-localstorage-adapter/master/localstorage_adapter.js"></script>
<script>
window.App = Ember.Application.create();
App.ApplicationStore = DS.Store.extend();
App.ApplicationSerializer = DS.LSSerializer.extend();
App.ApplicationAdapter = DS.LSAdapter.extend({
namespace: 'cars'
});
App.Car = DS.Model.extend({
make: DS.attr(),
model: DS.attr(),
features: DS.hasManyFragments('feature')
});
App.Feature = DS.ModelFragment.extend({
type: DS.attr(),
description: DS.attr()
});
App.Router.map(function () {
this.route('index', { path: '/' });
this.route('car', { path: '/car/:car_id'});
});
App.IndexRoute = Ember.Route.extend({
model: function() {
return this.store.find('car');
},
actions : {
add: function(model) {
var car = this.store.createRecord('car', {
make: 'Dodge',
model: 'Viper',
features: []
});
car.save();
}
}
});
App.CarRoute = Ember.Route.extend({
actions: {
add: function(model) {
model.get('features').createFragment({
type: 'Something',
description: 'Some desc'
});
model.save(); //*/
},
cancel: function(model) {
model.rollback();
}
}
});
</script>
<meta charset="utf-8">
<title>JS Bin</title>
</head>
<body>
<script type="text/x-handlebars" data-template-name="index">
{{#link-to 'index'}}Home{{/link-to}}
<ol>{{#each}}
<li>{{#link-to 'car' this}}{{name}} {{model}}{{/link-to}}</li>
{{else}}
<button {{action 'add' model}}>Add</button>
{{/each}}</ol>
</script>
<script type="text/x-handlebars" data-template-name="car">
{{#link-to 'index'}}Home{{/link-to}}
<dl>
<dt>Make</dt>
<dd>{{make}}
<dt>Model</dt>
<dd>{{model.model}}</dd>{{#each features}}
<dt>{{_view.contentIndex}}. {{type}}</dt>
<dd>{{description}}</dd>
{{/each}}
</dl>
<button {{action 'add' model}}>Add</button>
<button {{action 'cancel' model}}>Cancel</button>
</script>
</body>
</html>
I havent worked with data fragments but fragment is a model itself so the element/fragment is still there because you have created a record for it.
This record is stored in the ember store until you do something with it.
Rollback, via emberjs.com,does this - "If the model isDirty this function will discard any unsaved changes".
The model in this case seems to be the fragment. Rollback gets rid of the changes, which is what it is doing in your case, removing the type and desc values, but the record itself is still in the store.
If you want to get rid of the fragment altogether you would have to delete it. http://emberjs.com/guides/models/creating-and-deleting-records/
As-salamu-wa-alicum
Every body,
I have a index.html with
<script type="text/x-handlebars" data-template-name="application">
<div id="tabcontent" class="post" contenteditable="true">
{{outlet}}
</div>
</script>
applicationView.js with
App.applicationView = Ember.View.extend({
template:Ember.Handlebars.compile('welcomeTemplate.hbs')
,templateName:'application'
});
In js/templates/welcomeTemplate.hbs is
<div><p>Welcome</p></div>
In app.js I have
App.Router.map(function() {
// put your routes here
});
App.IndexRoute = Ember.Route.extend({ });
In console log I am getting
DEBUG: -------------------------------
DEBUG: Ember : 1.6.1
DEBUG: Handlebars : 1.1.2
DEBUG: jQuery : 1.10.2
DEBUG: -------------------------------
generated -> route:application Object { fullName="route:application"}
generated -> route:index Object { fullName="route:index"}
generated -> controller:application Object { fullName="controller:application"}
Rendering application with default view <(subclass of Ember.View):ember211> Object {
fullName ="view:application"}
generated -> controller:index Object { fullName="controller:index"}
**Could not find "index" template or view. Nothing will be rendered Object {
fullName="template:index"}**
log:
Transitioned into 'index'
Please tell me what is going on here and why am I not see the "Welcome" in browser at /index.html? How will I see "Welcome" in browser at /index.html?
Thank you very much
With best regards
Nadvi.
It doesn't make sense to have both a template and a templateName. Additionally application should be uppercase.
App.ApplicationView = Ember.View.extend({
template:Ember.Handlebars.compile('Hello {{name}}<br/>Name: {{input value=name}}')
});
Ember doesn't load files for you, so stating a hbs name won't do anything, it'll just think of it as a plain string you wanted to show in the page.
http://emberjs.jsbin.com/joyiqute/1/edit
I tried to implement user name displaying after log in. It displays in top menu. But top menu is getting displayed before log in, so it user name is getting cached.
I tried many approaches, and using volatile() is seems the best option, but it doesn't work. In this simple example currentTime calculates only once:
<script type="text/x-handlebars" data-template-name="application">
{{currentTime}}
</script>
App.ApplicationController = Ember.Controller.extend({
currentTime: function() {
console.log('computing value');
var time = new Date();
return time;
}.property().volatile()
});
Ember version 1.3
P.S. I prepared the gist to illustrate this issue: http://jsbin.com/OPUSoTaF/1
Actually, I can't find ANY way do display dynamic value in Ember's application template. Tried to display value from another controller using {{render}} helper, value still gets cached.
It seems that I just need to update value on ApplicationController from some other controller, and to do it in a proper way. Like this:
App.LoginController = Ember.Controller.extend({
needs: 'application',
setTime: function() {
this.get('controllers.application').set('currentTime', new Date());
}
});
The application to illustrate: http://jsbin.com/OPUSoTaF/4/edit
You can change ember properties and thus views using Handlebars {{action 'actionName'}} helper. You can add action helper to almost any UI element in your handlebars template an it is usually triggered on click. When triggered it calls actionName method on the controller.
Example:
Handlebars template:
<script type="text/x-handlebars" data-template-name="application">
<button {{action 'login'}}>Login</button>
{{loginTime}}
</script>
Controller:
App.ApplicationController = Ember.Controller.extend({
loginTime: 'User not logged in yet',
actions: {
login: function() {
// ... Do some login stuff ...
this.set('loginTime', new Date());
}
}
});
Working jsbin example is here: http://jsbin.com/udUyOXaL/1/edit
What I have so far:
App = Ember.Application.create({
LOG_TRANSITIONS: true
});
App.Router.map(function(match){
match('/').to('application');
match('/edit').to('edit');
});
App.ApplicationRoute = Ember.Route.extend({
redirect: function() {
this.transitionTo('edit');
},
events: {
startEdit: function( context ){
this.transitionTo( 'edit' );
}
}
})
App.EditRoute = Ember.Route.extend({
init: function(){
this._super()
console.log('EditRoute')
},
});
Handlebars:
<script type="text/x-handlebars" data-template-name = 'application'>
Hello World
{{ outlet main }}
</script>
<script type="text/x-handlebars" data-template-name = 'edit'>
<div class = 'edit-background'> Edit State: {{ title }} </div>
</script>
I have four questions:
When I open the application it just remains in the home page, is the redirectTo hook suppose to immediately redirect you to another state?
In addition, I have this events hash in AplicationRoute per suggestion from here: How to programmatically transition between routes using Ember.js' new Router. but I read through the answers and still am not sure how you are supposed to use it.
How do I test the router on the console? before you could navigate between the states by calling transitionTo commands, what do I do now?
For some odd reason, my application template seem to rendered twice, as in there are two 'Hello World' up there, and when try to add something like: <li>{{#linkTo edit}}edit{{/linkTo}}</li>
I get this error:
'Uncaught TypeError: Cannot read property 'container' of undefined -- ember.js:2223'
This is how you would initially load the editView/route/template on application start up:
Router
App.Router.map(function(match){
match('/').to('application',function(match){
match('/').to('edit')
})
})
ApplicationTemplate
<script type="text/x-handlebars" data-template-name="application">
{{outlet}}
</script>
EditTemplate
<script type="text/x-handlebars" data-template-name="edit">
I am embedded!
</script>
EditRoute
EditRoute = Ember.Route.extend({
renderTemplates:function () {
this.render('edit', {
into:'application'
});
})
I apologize if this has a painfully obvious answer but I am both a JS and Ember noob and I am having trouble finding a solution to what I think is a common scenario. Essentially, I have a multi-page app with html/css/js front end and a java back end with an exposed REST api. I have 1 app.js file that I include in all screens and multiple controllers, some of which only apply to individual screens.
EDIT: Forgot my question. My question is how do I delay the query to my server for my user data until my controller has an observer. Since the controller is present on multiple screens (which dont all need it) I do not want to blindly query on creation of the object since it would be wasteful. For now i have a hacky way of doing it where at the end of my inline script tag of a page I call the populate method. Below is what my code currently looks like.
Section of app.js:
App = Ember.Application.create();
User = Ember.Object.extend({
username: 'empty',
fullname: 'empty user'
});
App.UserDataSource = Ember.Object.extend({
fetchMyUser: function(callback) {
$.get('ncaa/user', function(data) {
callback(User.create({
username: data.username,
fullname: data.fullname}));
});
}
});
App.userDataSource = App.UserDataSource.create();
App.UserController = Ember.Object.extend({
content: null,
populate: function() {
var controller = this;
this.get('dataSource').fetchMyUser(function(data) {
controller.set('content', data);
});
}
});
App.userController = App.UserController.create({
dataSourceBinding: Ember.Binding.oneWay('App.userDataSource')
});
Ember.run.sync();
Section of index.html
<script type="text/x-handlebars">
Welcome, {{App.userController.content.fullname}}
</script>
....other code....
<script type="text/javascript">
$(document).ready(function() {
....other code....
App.userController.populate();
});
</script>
I am pretty sure my first steps will be modifying that handlebars template to extend Ember.View but would like to know what the community believes is the best practice. Also, is it wrong for me to try and put all of this in one app.js file? It would be ok to query on creation of my controller if it was only imported on screens that required the user to display.
The answer for my question did end up being in the Ember.View. Essentially what I do is override the init function of my view which adds the call to populate the necessary controller with data. The view is that instantiated via the handlebars template so no more unnecessary calls or hacky work around. Important changes below.
Index.html:
<script type="text/x-handlebars">
{{#view App.UserNameView }}
Welcome, {{fullName}}
{{/view}}
</script>
App.js:
App.UserNameView = Em.View.extend({
init: function() {
this._super();
App.userController.populate();
},
fullNameBinding: 'App.userController.content.fullname',
userNameBinding: 'App.userController.content.username'
});