MarionetteJS - Not able to render the data using toJSON function - backbone.js

I am using HandlebarsJS plugin to render my templates. I am getting error while i call the rendering function.
when i console the this.model.toJSON(), i am getting correct datas, as well I console the "homeEditTemp" I am getting my templates too..
But when i pass my data to template i am getting error as : Uncaught TypeError: undefined is not a function
here is my code :
define([
'jquery',
'underscore',
'backbone',
'marionette',
'hbs!scripts/templates/home/homeEditTemp'],
function ($,_,Backbone, Marionette, homeEditTemp) {
"use strict";
window.socialApp = window.socialApp || {};
socialApp.homeView = Backbone.Marionette.ItemView.extend({
initialize : function (model) {
this.model = model;
},
render : function () {
console.log(this.model.toJSON()) // works fine
console.log(homeEditTemp) // works fine.
this.$el.html(homeEditTemp(this.model.toJSON())); // throws the error..
}
});
return socialApp.homeView;
});
here is my handlebars template :
<form>
<div class="control-group">
<label for="firstName" class="control-label"> First name:</label>
<input id="firstName" name="firstName" type="text" value="{{firstName}}"/>
</div>
<div class="control-group">
<label for="lastName" class="control-label"> Last name:</label>
<input id="lastName" name="lastName" type="text" value="{{lastName}}"/>
</div>
<div class="control-group">
<label for="email" class="control-label">Phone number:</label>
<input id="email" name="email" type="text" value="{{email}}"/>
</div>
<button class="btn js-submit">Save</button>
</form>
Thanks in advance!
update :
when i manually assign the value, it works fine like this:
render : function (model) {
var obj = {
"firstName" : "testFirstName ",
"lastName" : " test lastName"
}
this.$el.html(homeEditTemp(obj));
}
what would be the issue?
when i console my model it show like this:
Object {model: s}model: s_changing: false_events: Object_pending: false_previousAttributes: Objectattributes: Objectchanged: Objectcid: "c6"__proto__: n__proto__: Object

At first you need to compile your template
var tpl = function () {
return Handlebars.compile(homeEditTemp);
}
Then you can use this
this.$el.html(tpl(this.model.toJSON()));

try it like this:
socialApp.homeView = Backbone.Marionette.ItemView.extend({
template:homeEditTemp,
initialize : function (model) {
this.model = model;
},
render : function () {
var output = this.template(this.model.toJSON());
this.$el.html(output);
return this;
}
});
but #vahan is right and you don't need to overwrite the render method usually, just have the template and model variable set and marionette will take care of it

I changed the model - implementation like this, it works for me.
initialize : function (arg) {
this.model = arg.model; //it works!
}
instead of :
initialize : function (model) {
this.model = model; //i am not directly got the model here..?
}

Related

Angularjs pass element to function

As per core we used this for get element but in AngularJS we get $scope context.
So, i tried this question but can't success.
Here is my try,
Controller
$scope.clickMe = function(ele) {
console.log(ele);
console.log(ele.id);
};
HTML
<div class="input-group">
<input type="number" id="test-id" ng-blur="clickMe($event.target);">
</div>
Q : How do i get element in function.
Thank You !
use : $event.currentTarget;
<div class="input-group">
<input type="number" id="test-id" ng-blur="clickMe($event);">
</div>
$scope.clickMe = function(ele) {
console.log(ele);
console.log(ele.currentTarget);
};
Fiddle" http://jsfiddle.net/h8to34ux/221/
your ng-blur event should send $event only like ng-blur="clickMe($event);"
then in your controller
$scope.clickMe = function(ele) {
console.log(angular.element(ele));
console.log(angular.element(ele).attr('id'));
};

Can't focus on Angular form text input after route change

I'm creating a form with Angular and Angular Messages. This form lies in a template that gets brought into the view with Angular Route. When I first load the form, everything functions properly. Then, when I load a different view and switch back to the form's view, I'm unable to focus on the text inputs. What's happening?
The HTML
<form name='submission' ng-submit='submit()'>
<label class='text-input-group' for='name'>
<div class='label'>Name</div>
<input id='name' name='name' ng-model='submissionName' type='text' required>
<div ng-messages='submission.name.$error' ng-if='submission.name.$touched'>
<div ng-message='required'>* Please enter your name</div>
</div>
</label>
<label class='text-input-group' for='email'>
<div class='label'>Email</div>
<input id='email' name='email' ng-model='submissionEmail' type='email' required>
<div ng-messages='submission.email.$error' ng-if='submission.email.$touched'>
<div ng-message='required'>* Please enter your email address</div>
<div ng-message='email'>* Please enter a valid email address</div>
</div>
</label>
<label class='text-input-group' for='message'>
<div class='label'>Message</div>
<textarea id='message' name='message' ng-model='submissionMessage' ng-maxlength='2000' maxlength='2000' required></textarea>
<div ng-messages='submission.message.$error' ng-if='submission.message.$touched'>
<div ng-message='required'>* No message?</div>
<div ng-message='maxlength'>* Your message unfortunately can't exceed 20,000 characters</div>
</div>
</label>
<label class='checkbox-input-group' for='send-user-a-copy'>
<div class='label'>Send me a copy</div>
<input id='send-user-a-copy' name='sendUserACopy' ng-init='submissionSendUserACopy = false;' ng-model='submissionSendUserACopy' type='checkbox'>
</label>
<button type='submit'>Button</button>
</form>
The JavaScript
var contact = angular.module('app.contact', ['ngRoute']);
contact.config(['$routeProvider', function($routeProvider) {
$routeProvider.when('/contact', {
templateUrl: 'partials/contact.html',
controller: 'ContactController'
});
}]);
contact.controller('ContactController', ['$scope', function($scope) {
$scope.reset = function() {
$scope.submissionName = '';
$scope.submissionEmail = '';
$scope.submissionMessage = '';
$scope.submissionSendUserACopy = '';
$scope.submission.$setPristine();
}
$scope.$on('$routeChangeSuccess', function() {
console.log($scope.submission);
$scope.reset();
});
$scope.submit = function() {
if($scope.submission.$valid) {
console.log({
'name' : $scope.submissionName,
'email' : $scope.submissionEmail,
'message' : $scope.submissionMessage,
'sendUserACopy' : $scope.submissionSendUserACopy
});
}
}
}]);
Any answers / suggestions would be greatly appreciated. Thank you!
I wrote this to solve the issue with focus not applying on route changes in Angular.
import { Directive, ElementRef, AfterContentInit } from '#angular/core';
#Directive({
selector: '[focusOnInit]'
})
export class FocusDirective implements AfterContentInit {
constructor(public el: ElementRef) {}
ngAfterContentInit() {
this.el.nativeElement.focus();
}
}
usage
<input type="text" focusOnInit>
There is an attribute autofocus introduced in HTML5. I would suggest you adding that attribute in the first input element.
<input type="text" ng-model="firstName" autofocus />
But that has a limitation too!! Currently, browsers only focus on the input element directive on page load. So you will fall into the same problem that you are currently facing. So you can simply add an Angular directive with the same name i.e. autofocus which will programmatically focus the element as that directive is executed when the same view is loaded again.
myApp.directive('autofocus', [function() {
return {
restrict: 'A',
link: function(scope, element) {
element[0].focus();
}
};
}]);
(This is the format in Angular 1, please write it in Angular 2 if you are using Angular 2.)
Since even the same view has been loaded before, Angular will execute all the directives when the view is loaded again, this directive will focus the element after you switch back from another view.

Angular watch form input doesnt work

I have a form in html page :
<div ng-controller="ctrl as c">
<form name="myForm">
<input type="text" name="myInput" require/>
</form>
</div>
I want to watch changes of input in my controller, so I did like this :
angular.module('app').controller('ctrl', ctrl);
ctrl.$inject = ['$scope'];
function ctrl($scope) {
var vm = this;
$scope.$watch('myForm.myInput', function (value) {
//check validity
});
}
But when I change input value, nothing happen in controller.
Any idea?
<div ng-controller="ctrl as c">
<form name="myForm">
<input type="text" name="myInput" ng-model="c.myInput" require/>
</form>
</div>
Controller
function ctrl($scope) {
var vm = this;
vm.myInput = 'hello';
$scope.$watch(function(){
return vm.myInput;
}, function(newValue, oldValue) {
console.log(newValue)
});
}
The $scope.watch() function creates a watch of some variable.
So you need to bind a scope to your input and creates watch for that variable.
View:
<input type="text" ng-model="myInput" name="myInput" require/>
Controller:
function ctrl($scope) {
var vm = this;
$scope.myInput = "";
scope.$watch('myInput', function(newValue, oldValue) {
// Your logic
});
}
I believe watching the entire form may create a performance hit, still they are ways to watch multiple variable using watch
1. Create a $scope object like
$scope.form = {
name:"My Name",
Id:"My Id:,
....
}
Now you can use $watch with a third variable 'true'
$scope.$watch('form', function(newVal, oldVal){
console.log('changed');
}, true);
Html:
<input type="text" ng-model="form.name" name="myName" require/>
<input type="text" ng-model="form.id" name="myId" require/>
2. Use $scope.$watchCollection
$scope.$watchCollection('[item1, item2]', function(newValues, oldValues){
// You logic here
// newValues and oldValues contain the new and old value of the array
});
Also check this post for different ways of listening changes to multiple elements using $watch

Angular JS: how to stop two way binding from happening

I have a very simple script that contains angular js
<script>
var delightApp = angular.module('delightmeter', []);
delightApp.controller('delightController', function ($scope) {
$scope.delightScore = 0;
$scope.test = function () {
if (isNaN($scope.delightScore)) {
// do not bind if this happens
}
}
});
</script>
The html of the above script is
<div id="angularapp" data-ng-app="delightmeter" data-ng-controller="delightController">
<input id="Text1" type="text" data-ng-model="delightScore" />
{{delightScore}}
<input id="Button1" type="button" value="button" data-ng-click="test()"/>
</div>
As we know in angular two way binding happens whatever may be the value in $scope.delightScore it gets bound to the html page.
Is there any way to stop this binding from happening ?
Rather than binding to the variable directly, Bind to a function that does your check
<div id="angularapp" data-ng-app="delightmeter" data-ng-controller="delightController">
<input id="Text1" type="text" data-ng-model="delightScore" />
{{ValideDelightScore()}}
<input id="Button1" type="button" value="button" data-ng-click="test()"/>
</div>
And in your controller define:
$scope.ValideDelightScore = function () {
if (isNaN($scope.delightScore)) {
return "";
}else{
return $scope.delightScore
}
}
There is no way to do that because you are explicity binding the model in both scopes. And even if you could you should'n mess with the Angular life-cycle, or you are going to have a bad time.
The right way to achieve what you need is, or using solution purposed by #Shivas Jayaram, or use a filter in where you don't want to display the model if isNaN.
angular.module('myApp.filters', [])
.filter('NaNFilter', function($moment, $translate) {
return function(value) {
if(isNaN(val)) {
return '';
}
return value;
};
});
And in your template:
<div id="angularapp" data-ng-app="delightmeter" data-ng-controller="delightController">
<div>Show delightScore if !NaN: {{delightScore | NaNFilter}}</div>
<input id="Text1" type="text" data-ng-model="delightScore" />
{{delightScore}}
<input id="Button1" type="button" value="button" data-ng-click="test()"/>
</div>

Unable to submit data via form

I have a simple form:
<form ng-submit='addMessage()'>
<input type='text' ng-model='chatMessage' placeholder='chat here' />
<input type='submit' value='chat' />
</form>
And at the moment, a very simple function:
$scope.addMessage = function() {
console.log($scope.chatMessage);
}
The console logging is just logging undefined, no matter what I type into the input box. Clearly I'm missing something, but I'm not sure what that is.
Depending on the way forms are used, sometimes $scope is out of context between the controller on the form. This is because addMessage(), and chatMessage are not on the same level of the $scope hierarchy.
One way to fix this is to create a container for your form items:
$scope.cont = {};
$scope.addMessage = function() {
console.log($scope.cont.chatMessage);
}
And in the form:
<input type="text" ng-model="cont.chatMessage" placeholder="chat here"/>
This is also something you should definitely read if you are going to use angular more: http://jimhoskins.com/2012/12/14/nested-scopes-in-angularjs.html
Look for that fiddle maybe you missed something different .
<div ng-app="app">
<div ng-controller="mainCtrl">
<form ng-submit='addMessage()'>
<input type='text' ng-model='chatMessage' placeholder='chat here' />
<input type='submit' value='chat' />
</form>
<pre>{{msg | json}}</pre>
</div>
</div>
JS:
var app = angular.module("app", []);
app.controller("mainCtrl", function ($scope) {
$scope.msg = [];
$scope.addMessage = function () {
$scope.msg.push($scope.chatMessage);
console.log($scope.chatMessage);
$scope.chatMessage = "";
}
});
This should work:
<form ng-submit='addMessage(chatMessage)'>
<input type='text' ng-model='chatMessage' placeholder='chat here' />
<input type='submit' value='chat' />
</form>
And in your controller:
$scope.addMessage = function(msg) {
console.log(msg);
}
UPDATE
based on your comments i think you are looking for something like this:
$scope.messages = [];
$scope.$watch('messages', function(newMessage) {
alert('hey, a message was added ! :' +newMessage);
}, true);
$scope.addMessage = function(msg) {
$scope.messages.push(msg);
};
Angular has so called watches, the watched function will trigger everytime when a new message is addded to the array. For more information about watches refer to the docs

Resources