Output in multiple parts of the page - javascript

index.html:
<div id="section_a">
<script type="text/x-handlebars" data-template-name="index">
First value: {{input type="text" value=one}}<br>
Second value: {{input type="text" value=two}}<br>
Result: {{result}}
</script>
</div>
<div id="section_b">
<!-- Display {{result}} here aswell -->
</div>
application.js
App.IndexController = Ember.ObjectController.extend({
one: 0,
two: 0,
result: function() {
return this.get('one') + this.get('two');
}.property('one', 'two')
});
I have a section of a page where I have some Ember interactions - a user inputs some values and a calculated result is displayed.
I now want to have the calculated result displayed in another part of the page that is outside the defined template, how would I accomplish this?

You could bind that property to the application controller and then use it anywhere you want in the application. For example:
App.ApplicationController = Ember.ObjectController.extend({
needs: ['index'],
indexResult: Ember.computed.alias('controllers.index.result')
});
Now you can use it anywhere within the application you want. Just tell the outlet's controller to need the application controller, then call that property in the template. Like so:
App.FooController = Ember.ArrayController.extend({
needs: ['application'],
//...
});
In the Foo template:
{{controllers.application.indexResult}}
Or, if you are within the application scope you can just do:
{{indexResult}}

One simple and straight forward solution would be:
<script type="text/x-handlebars" data-template-name="index">
<div id="section_a">
First value: {{input type="text" value=one}}<br>
Second value: {{input type="text" value=two}}<br>
Result: {{result}}
</div>
<div id="section_b">
<!-- Display {{result}} here aswell -->
</div>
</script>

You can also set up another outlet that can be used to display the "result". You can read more about using outlets in the Ember.js Guides at http://emberjs.com/guides/routing/rendering-a-template/

Related

EmberJS passing variable to the layout

I have a really basic test app. It has 2 pages an empty index and a login form on an other page. And I would like to know how can I pass variables to the layout which is the same on every page (user name/status for display it and display login/logout by status).
Or the best solution could be something like this: pass a user model to the AppController which is available from anywhere (like login page or login modals) and If I change and save the data the site template is just changing by the passed variables.
I was trying to find a good way, I find a few ones but none of them was working :( If you know a working way please share me or show me what is the solution.
Here is my code: the JS I have:
App = Ember.Application.create();
App.ApplicationController = Ember.Controller.extend({});
/* *** Index *** */
App.IndexView = Ember.View.extend({
layoutName: 'app_view'
});
App.IndexController = Ember.Controller.extend({
});
/* *** LOGIN *** */
App.Router.map(function () {
this.resource("login");
});
App.LoginView = Ember.View.extend({
layoutName: 'app_view'
});
App.LoginController = Ember.Controller.extend({
login: function() {
// blah blah
}
});
Layout template:
<script type="text/x-handlebars" data-template-name="app_view">
<header id="site">
{{#link-to "index"}}Index{{/link-to}}
{{#link-to "login"}}Login{{/link-to}}
{{variablaWhatIWant}}
</header>
<hr />
<section id="content">
{{yield}}
</section>
<hr />
<footer id="main">
Footer
</footer>
</script>
2 view templates:
<script type="text/x-handlebars" data-template-name="index">
Hello INDEX page!
</script>
<script type="text/x-handlebars" data-template-name="login">
<form class="form-horizontal" {{action "login" on="submit"}}>
<div class="control-group">
Username: {{input value=username type="text"}}
</div>
<div class="control-group">
Password {{input value=password type="password"}}
</div>
<button type="submit" class="btn">Log in!</button>
</form>
</script>
Thank you very much! :)
You have the right idea, see managing dependancies between controllers http://emberjs.com/guides/controllers/dependencies-between-controllers
just set the needs property, and you can access that controller from any other
App.LoginController = Ember.Controller.extend({
needs: ['application'],
login: function() {
this.authenticate(this.get('username'), this.get('password')).then(function(user) {
this.set('controllers.application.user', user);
},
function(err) {
//auth err
}
}
});

Angular data - having trouble binding updated values to scope (using slider)

I'm trying to use Angular to create a tool that accepts user input from a slider tool, and automatically updates an "estimate" field whenever the values are changed. However, the data only seems to be binding on the way to the view; the user input is displayed, but doesn't seem to register in the scope.
Here's the HTML:
<h3 ng-controller="calcController" ng-model="estimate" class="floating-menu">${{estimate}}</h3>
<form ng-controller="calcController" method="post" action="/estimate">
<div class="container">
<div class="vals">${{values.insurance}}</div>
<div id="insurance-slider">
<slider floor="0" ceiling="250" value="125" step="25" precision="2" ng-model="values.insurance" ng-change="changeVal()" translate="currencyFormatting"></slider>
</div>
<div class="container">
<div class="vals">${{values.lease}}</div>
<div id="lease-slider">
<slider floor="0" ceiling="250" value="125" step="25" precision="2" ng-model="values.lease" translate="currencyFormatting"></slider>
</div>
</div>
</form>
Here's the Angular:
//create the module
angular.module('Breeze', ['ngRoute', 'ngResource', 'ui.slider'])
.config(function($routeProvider) {
$routeProvider
// route for the calculator page
.when('/', {
templateUrl: 'partials/calculator.html',
controller: 'calcController'
});
})
// create the controller and inject Angular's $scope
.controller('calcController', function($scope, $http) {
$scope.values = {
// Default values
insurance: 125,
lease: 125,
};
$scope.estimate = $scope.values.insurance + $scope.values.lease
}
// Formatting for scale bar
$scope.currencyFormatting = function(value) {
return value.toString() + " $";
}
})
I've tried adding a $watch and a $broadcast function but can't seem to get them working.
This is what it looked like in Angular:
$scope.$watch("values", function(newVal, oldVal, scope) {
scope.estimate = addVals();
})
$scope.changeVal = function() {
$scope.estimate = addVals();
console.log('hi')
$scope.estimate = $scope.values.insurance + $scope.values.lease
}
Ideas?
You are using two nested ng-controller="calcController"in your HTML. Hence two instanciations of the controller (two $scope) which will have their own estimate value, so when you update the inner estimate, the upper one is not aware of that.
You should remove the second ng-controller in your <form> (if the controller were different, then you would put the estimate variable in an object such as $scope.model.estimate so properties inheritance between the two controllers actually work. But in your case there is no reason to have two controllers).
Also, you should remove that ng-model="estimate" in your <h3> tag, which has no effect.
Just setting them equal in the beginning wont work. In your view, instead of having an estimate field just use this
<div ng-controller="calcController" ng-app="Breeze">
<h3 ng-model="estimate" class="floating-menu">${{values.insurance + values.lease }}</h3>
<form method="post" action="/estimate">
<div class="container">
<div class="vals">${{values.insurance}}</div>
<div id="insurance-slider">
<slider floor="0" ceiling="250" value="125" step="25" precision="2" ng-model="values.insurance" ng-change="changeVal()" translate="currencyFormatting"></slider>
</div>
<div class="container">
<div class="vals">${{values.lease}}</div>
<div id="lease-slider">
<slider floor="0" ceiling="250" value="125" step="25" precision="2" ng-model="values.lease" translate="currencyFormatting"></slider>
</div>
</div>
</div>
</form>
</div>
This will keep them adding as the values change.
Another thing that would be breaking is that you have two controller calls to the same controller and no app. Need to change it as below with the new div and remove the rest of the ng-controllers.
Also, make sure that you have the ui slide javascript file included on your page.
Did you try to bind to object instead of primitive type?
$scope.values.estimate = $scope.values.insurance + $scope.values.lease
see similar question here:
Angularjs: 2 way binding not working in included template
Here is a fiddle http://jsfiddle.net/U3pVM/9330/

angularjs dynamic model in template

I need to create dynamic inputs, textareas..etc. So for each input type I have a separate template. So a text field template could look like this:
<script type="text/ng-template" id="/input.html">
<input type="text" ng-model="model" />
</script>
and what I am trying to achieve is something like this:
<div ng-include="" src="'/input.html'" ng-init="model = var1"></div>
<div ng-include="" src="'/input.html'" ng-init="model = var2"></div>
so I can create text fields with the same template and have a different model for each one. That works actually and gets the data passed, but if I type something in the text field it doesn't get applied to the scope variable.
Here's a fiddle to illustrate this: http://jsfiddle.net/uAm99/2/
You could try to implement this feature in "angular directive way". It can empower the HTML tag, such as reusable template (just mentioned in your implementation). Here is a simple example:
HTML
<body ng-app="myApp">
<div ng-controller="myCtrl">
<custom-input data="var1"></custom-input>
<custom-input data="var2"></custom-input>
{{var1}}
{{var2}}
</div>
</div>
JS
angular.module("myApp",[])
.controller("myCtrl",function($scope){
$scope.var1 = "foo";
$scope.var2 = "bar";
})
.directive("customInput",function(){
return {
restrict:'E',
scope: {
data:"="
},
template: '<input type="text" ng-model="data" />'
};
});
And this is a jsfiddle demo
Hope it helpful.

Render view component with parameters into named outlet ember.js

I have 2 named outlets in my application template, slider-area and pre-footer. Is there a way to pass view components that take parameters, as in the main-slider component shown in the index template, to a named outlet? So I would need to pass {{main-slider sliders=filteredSlider}} to the outlet {{outlet "slider-area"}} in the index template?
I have come from rails so forgive my thinking if this is not how ember does it. One could specify yield :slider_area in the application template and then wrap any content for this area in a content_for :slider_area block. Is a similar approach available in ember?
index.html
<script type="text/x-handlebars" data-template-name="application">
{{panasonic-topbar}}
<div id="batterywrap">
{{outlet "slider-area"}}
<div class="index_contents">
<div class="index_contents_inner">
<div class="main_area">
{{outlet}}
</div>
</div>
</div>
</div>
{{panasonic-footer}}
</script>
<script type="text/x-handlebars" data-template-name="index">
# Something like {{outlet "slider-area" render main-slider sliders="filteredSlider}} ?
{{main-slider sliders=filteredSlider}}
{{partial "social_footer"}}
</script>
app.js
App.IndexController = Ember.ObjectController.extend({
filteredSlider: function(){
return this.get('sliders').filterBy('page', 'index');
}.property('sliders.#each.page')
});
App.IndexRoute = Ember.Route.extend({
model: function() {
return Ember.RSVP.hash({
sliders: this.store.find("slider")
});
}
});
Ok, so I have a solution to this issue, rather than trying to pass a view component within a template to a specific outlet (the ruby on rails way), the key is to create a template, not a component, and render this from within the Route to the specific outlet.
When rendered from Route, the slider template has access to all of the functions in the scope of the Routes controller, so we namespace the functions/arguments universally across all controllers that will use this template and our dynamic parameters should work.
So below in the IndexRoute we define the data that we send to the controller, sliders, we also specify that we want to render normal content in the default outlet using this.render();, and then we render our shared slider template into the named outlet "slider-area". Then in our controller, we filter the models data to our specification and we name this function batterySliders across all controllers that use this feature.
app.js
App.IndexController = Ember.ObjectController.extend({
batterySliders: function(){
return this.get('sliders').filterBy('page', 'index');
}.property('sliders.#each.page')
});
App.IndexRoute = Ember.Route.extend({
model: function() {
return Ember.RSVP.hash({
sliders: this.store.find("slider"),
});
},
renderTemplate: function(){
this.render();
this.render("slider", {outlet: "slider-area"});
}
});
index.html
<script type="text/x-handlebars" data-template-name="slider">
{{panasonic-navigation tagName="div" classNames="gnavi_area"}}
<div class="slider_wrap">
<div id="slider" class="main_slider">
{{#each slider in batterySliders}}
<div class="slider_area slider0{{unbound slider.id}} {{unbound slider.background}}">
<div class="slider_inner">
<div class="inner0{{unbound slider.id}}">
<img {{bind-attr src="slider.image" alt="slider.image"}} class="nosp"/>
<img {{bind-attr src="slider.sm_image" alt="slider.sm_image"}} class="sp"/>
</div>
</div>
</div>
{{/each}}
</div>
</div>
</script>
application.html
<script type="text/x-handlebars" data-template-name="application">
{{panasonic-topbar}}
<div id="batterywrap">
<div class="content_head">
{{outlet "slider-area"}}
</div>
<div class="index_contents">
<div class="index_contents_inner">
<div class="main_area">
{{outlet}}
</div>
</div>
</div>
</div>
{{panasonic-footer}}
</script>

emberjs append works but raises Assertion Failed error

I'm new to ember I am trying to append a template to another and it seems to work but it raises an error, can you please explain why?
The error:
Assertion failed: You cannot append to an existing Ember.View. Consider using Ember.ContainerView instead
This is the code in app.js
App.NewStickie = Ember.View.extend({
click: function(evt){
var stickie = Ember.View.create({
templateName: 'stickie',
content: 'write your notes here'
});
stickie.appendTo('#stickies');
}
});
These are the contents of index.html
<script type="text/x-handlebars">
{{#view App.NewStickie}}
<button type="button" class="btn btn-success">
New
</button>
{{/view}}
{{outlet}}
</script>
<script type="text/x-handlebars" id="index">
<div id="stickies">
{{#each item in model}}
<div class="stickie" contenteditable="true">
{{#view App.DeleteStickie}}
<span class="glyphicon glyphicon-trash"></span>
{{/view}}
<div contenteditable="true">
{{item.content}}
</div>
</div>
{{/each}}
</div>
</script>
<script type="text/x-handlebars" data-template-name="stickie">
<div class="stickie">
{{#view App.DeleteStickie}}
<span class="glyphicon glyphicon-trash"></span>
{{/view}}
<div contenteditable="true">
{{view.content}}
</div>
</div>
</script>
Each view in ember have a template, for example:
foo_view.js
App.FooView = Ember.View.extend({
templateName: 'foo'
})
foo template
<script type="text/x-handlebars" data-template-name="index">
<div id=myFooView>Foo</div>
</script>
You are trying to insert a view inside of other in that way:
App.BarView.create().appendTo('#myFooView')
This isn't allowed. You can use the {{view}} handlebars helper to render a view inside other like that:
foo template
<script type="text/x-handlebars" data-template-name="index">
<div id=myFooView>
Foo
{{view App.BarView}}
</div>
</script>
But I think that you want this working dynamically. So you can use the ContainerView, like described by the error message:
App.StickiesView = Ember.ContainerView.extend({
click: function() {
var stickie = Ember.View.create({
templateName: 'stickie',
content: 'write your notes here'
});
this.pushObject(stickie);
}
})
I see in your code a lot of views with the click event, ember encourage you to use actions, this give more flexibility, error/loading handling etc. I think is a good idea to use it.
I hope it helps
You should probably read this guide that explains that ContainerView is. Also, I don't think it's necessary to create another View to append a template to another template.

Categories

Resources