I have a backbone View like follows:
app.View.WelcomeProfil = Backbone.View.extend({
initialize : function(){
this.header = document.createElement('div');
this.$header = $(this.header);
this.render();
},
model : new app.Model.AccountProfile(),
template : {
header : _.template($('#welcome-profile-header').html()),
body : _.template($('#welcome-profile').html()),
error : _.template($('#welcome-profile-error').html())
},
attributes : {
'class' : 'form-horizontal row-fluid'
},
tagName : 'form',
next : function(){
var self = this;
_.each(this.$el.serializeArray(), function(value){
self.model.set(value.name, value.value);
});
this.model.save(null, {
success : function(model){
self.trigger('next');
},
error : function(model){
self.$el.append(self.template.error());
}
});
},
previous : function(){
this.trigger('previous');
},
render: function(){
var self = this;
this.$header.html(this.template.header());
this.model.fetch({
success : function(model){
self.$el.html(self.template.body(model.toJSON()));
},
error : function(model){
self.$el.html(self.template.body(model.toJSON()));
self.$el.append(self.template.error());
}
});
return this;
},
destroy : function(){
this.$header.remove();
this.remove();
this.trigger('remove', this);
}
});
My template looks like follows
<script type="text/template" id="welcome">
<div class="modal-header">
</div>
<div class="modal-body">
</div>
<div class="modal-footer">
<# if (previous) { #><input type="button" class="pull-left" value="<fmt:message key="foobar.form.previous"/>"/><# } #>
<# if (next) { #><input type="button" class="pull-right" value="<fmt:message key="foobar.form.next"/>"/><# } #>
<# if (finish) { #><input type="button" class="pull-right" value="<fmt:message key="foobar.form.finish"/>"/><# } #>
</div>
This is the template which is inserted inside modal-body
<script type="text/template" id="welcome-profile">
<fieldset>
<div class="control-group">
<label class="control-label" for="firstName"><fmt:message key="foobar.user.firstName"/></label>
<div class="controls">
<input type="text" class="input-block-level" name="firstName" required="required" placeholder="<fmt:message key="foobar.user.firstName"/>" value="<#= firstName #>">
</div>
</div>
<div class="control-group">
<label class="control-label" for="lastName"><fmt:message key="foobar.user.lastName"/></label>
<div class="controls">
<input type="text" class="input-block-level" name="lastName" required="required" placeholder="<fmt:message key="foobar.user.lastName"/>" value="<#= lastName #>">
</div>
</div>
<div class="control-group">
<label class="control-label" for="jobTitle"><fmt:message key="foobar.user.jobTitle"/></label>
<div class="controls">
<input type="text" class="input-block-level" name="jobTitle" required="required" placeholder="<fmt:message key="foobar.user.jobTitle"/>" value="<#= jobTitle #>">
</div>
</div>
I want that when the user clicks next ...somehow i should be able to check if the first name , last name and job title fields are filled up or not..? Is this possible.
Create a validate method on your model like so: http://backbonejs.org/#Model-validate
Once created, backbone will automatically invoke this method before running the save, and you can bind to the invalid event to update the view with the error.
Related
I have an angularJS component that displays alerts when something goes wrong while submitting, these alerts are not auto dismissed by design.
But, when the user fix all errors (there can be many alerts displayed on the screen) and submit I want to dismiss these alerts.
Based on this example https://jsfiddle.net/uberspeck/j46Yh/
I did something like this:
(function(){
var mainApp = angular.module("myApp");
function AlertsCtrl($scope, alertsManager) {
$scope.alerts = alertsManager.alerts;
}
mainApp.factory('alertsManager', function() {
return {
alerts: {},
addAlert: function(message, type) {
this.alerts[type] = this.alerts[type] || [];
this.alerts[type].push(message);
},
clearAlerts: function() {
for(var x in this.alerts) {
delete this.alerts[x];
}
}
};
mainApp.controller("addUserCtrl", ['Restangular', 'alertsManager', '$alert', 'roles', '$window' , function(Restangular, alertsManager, $alert, roles, $window) {
var that = this;
init();
that.submit = function() {
var data = {
user : that.name,
role : that.role.serverName,
credentials : that.password1
}
Restangular.all("admin").all("user").all("add").post(data).then(function() {
//$alert({title: 'Add User:', content: 'Completed succefully', type: 'success', container: '#alert', duration: 5, show: true});
alertsManager.addAlert('Completed succefully', 'alert-success');
init();
alertsManager.clearAlerts();
}, function(reason) {
//$alerts{title: 'Add User:', content: reason.data.error, type: 'danger', container: '#alert', show: true});
alertsManager.addAlert(reason.data.error, 'alert-error');
});
}
function init() {
that.name = "";
that.roles = roles;
that.role = that.roles[0];
that.password1 = "";
that.password2 = "";
}
}]);
})();
HTML:
<div ng-controller="addUserCtrl as ctrl">
<div class="container-fluid">
<div class="row">
<div class="col-md-8 col-md-offset-2">
<div class="panel panel-default">
<form class="form-horizontal" ng-submit="ctrl.submit()">
<div class="panel-heading">Add User</div>
<div class="panel-body">
<div class="form-group">
<label for="name" class="col-sm-3 control-label">User Name: <span class="required">*</span></label>
<div class="col-sm-8">
<input type="text" class="form-control" id="name" ng-model="ctrl.name"></input>
</div>
</div>
<div class="form-group">
<label for="role" class="col-sm-3 control-label">Role: <span class="required">*</span></label>
<div class="col-sm-8">
<select class="form-control" id="role" ng-model="ctrl.role" ng-options="opt.displayName for opt in ctrl.roles"></select>
</div>
</div>
<div class="form-group">
<label for="password1" class="col-sm-3 control-label">Password: <span class="required">*</span></label>
<div class="col-sm-8">
<input type="password" class="form-control" id="password1" ng-model="ctrl.password1"></input>
</div>
</div>
<div class="form-group">
<label for="password2" class="col-sm-3 control-label">Re-enter Password: <span class="required">*</span></label>
<div class="col-sm-8" ng-class="{'has-error' : ctrl.password1 != ctrl.password2}">
<input type="password" class="form-control" id="password2" ng-model="ctrl.password2"></input>
<p class="help-block" ng-if="ctrl.password1 != ctrl.password2">Passwords don't match</p>
</div>
</div>
</div>
<div class="panel-footer">
<button type="submit" class="btn btn-default" ng-disabled="!ctrl.name || !ctrl.password1 || !ctrl.password2 || ctrl.password1 != ctrl.password2">OK</button>
</div>
<div ng-controller="AlertsCtrl">
<div ng-repeat="(key,val) in alerts" class="alert {{key}}">
<div ng-repeat="msg in val">{{msg}}</div>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
But I'm getting:
Uncaught SyntaxError: Unexpected end of input
angular.js:14747 Error: [ng:areq] http://errors.angularjs.org/1.4.3/ng/areq?p0=addUserCtrl&p1=not%20aNaNunction%2C%20got%20undefined
You did not complete all brackets correctly.
Below should be like this:
mainApp.factory('alertsManager', function() {
return {
alerts: {},
addAlert: function(message, type) {
this.alerts[type] = this.alerts[type] || [];
this.alerts[type].push(message);
},
clearAlerts: function() {
for(var x in this.alerts) {
delete this.alerts[x];
}
}
}
});
You forgot to complete the factory by });.
And that is why indentation is so important.
Hope this may help you.
in this code of HTML, we get input text value and send to the Angular controller
so they get to work as defined in code.
<div class="row" ng-controller="RegionController">
<div class="col-lg-12" >
<div class="hpanel">
<div class="panel-heading">
<!-- <div panel-tools></div> -->
<h2>Region Master Entry</h2>
</div>
<div class="panel-body">
<!--change form name,and submit controller name-->
<form role="form">
<div class="form-group">
<label class="col-sm-2 control-label">Region Name</label>
<div class="col-sm-10">
<input type="text" placeholder="please enter Region name" class="form-control m-b" required name="Region Name" ng-model="formRegionData.region_name" >
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">Region Code</label>
<div class="col-sm-10">
<input type="text" placeholder="please enter Region code" class="form-control m-b" required name="Region Code" ng-model="formRegionData.region_code">
</div>
</div>
<div class="form-group">
<div class="col-sm-3">
<label>Active</label>
</div>
<div class="checkbox checkbox-success col-sm-9">
<input id="checkbox3" type="checkbox" checked="" ng-model="formRegionData.status">
<label for="checkbox3">
</label>
</div>
</div>
<div class="form-group">
<div class="col-sm-4"></div>
<div class="col-sm-8">
<button class="btn btn-sm btn-primary btn-xl text-right" type="submit" ng-click="createRegion()"><strong> Save Region </strong></button>
</div>
</div>
{{formRegionData | json}}
</form>
</div>
</div>
</div>
</div>
"{{formRegionData | json}}" this will return in HTML input text result of but not send data to the controller
in Controller the code is written as
.controller('RegionController', function( $scope , regionService) {
$scope.createRegion = function() {
debugger;
vm.processing = true;
vm.message = '';
console.log(formRegionData);
regionService.SaveRegion( formRegionData )
.then(function(data) {
debugger;
//console.log(data);
//.success(function(data) {
vm.processing = false;
vm.storyData = {};
vm.message = data.message;
});
}
})
and my service to work according to Controller
.factory('regionService',function($http ){
var regionFactory = {};
regionFactory.SaveRegion = function(formRegionData) {
debugger;
return $http.post('/api/region/', formRegionData);
}
return regionFactory;
});
You have missed $scope
$scope.createRegion = function() {
debugger;
$scope.processing = true;
$scope.message = '';
console.log($scope.formRegionData);
regionService.SaveRegion($scope.formRegionData )
.then(function(data) {
debugger;
//console.log(data);
//.success(function(data) {
$scope.processing = false;
$scope.storyData = {};
$scope.message = data.message;
});
}
})
and remove ng-click="createRegion()" in your button control and add this code in your form tag by ng-submit. like,
<form ng-submit="createRegion()" role="form">
You have missed of $scope in form region data
Here is the link Jsfiddle
JS
angular.module('myApp', ['ngStorage'])
.controller('RegionController', function($scope, regionService) {
var vm = this;
$scope.createRegion = function() {
debugger;
vm.processing = true;
vm.message = '';
regionService.SaveRegion($scope.formRegionData)
.then(function(data) {
debugger;
//console.log(data);
//.success(function(data) {
vm.processing = false;
vm.storyData = {};
vm.message = data.message;
});
}
}).factory('regionService', function($http) {
var regionFactory = {};
regionFactory.SaveRegion = function(formRegionData) {
debugger;
return $http.post('/api/region/', formRegionData);
}
return regionFactory;
});
Template for form submission. This page will display the form template. Initially it shows the TItle,Full Name. On clicking the 'Add Tags' link new input fields is been generated for entering tags.
On submit, the field input(story.tag) is not been included on RequestPayload
<form novalidate ng-submit="save()">
<div>
<label for="title">Title</label>
<input type="text" ng-model="story.title" id="title" required/>
</div>
<div>
<label for="firstName">Full Name</label>
<input type="text" ng-model="story.fullname" id="fullname" required/>
</div>
<div ng-controller="Note" >
<div ng-repeat="story in items ">
<label>Tag {{$index+1}}:</label>
<input type="text" ng-model="story.tag" id="tag" required/>
</div>
<a ng-click="add()">Add Tags</a>
</div>
<button id="save" class="btn btn-primary">Submit Story</button>
</form>
script :- app.js
angular.module("getbookmarks", ["ngResource"])
.factory('Story', function ($resource) {
var Story = $resource('/api/v1/stories/:storyId', {storyId: '#id'});
Story.prototype.isNew = function(){
return (typeof(this.id) === 'undefined');
}
return Story;
})
.controller("StoryCreateController", StoryCreateController);
function StoryCreateController($scope, Story) {
$scope.story = new Story();
$scope.save = function () {
$scope.story.$save(function (story, headers) {
toastr.success("Submitted New Story");
});
};
}
//add dynamic forms
var Note = function($scope){
$scope.items = [];
$scope.add = function () {
$scope.items.push({
inlineChecked: false,
tag: "",
questionPlaceholder: "foo",
text: ""
});
};
}
The story object inside ng-repeat is in another scope. This JSFiddle should do what you are looking for.
<div ng-app>
<div ng-controller="NoteCtrl">
<form novalidate ng-submit="save()">
<div>
<label for="title">Title</label>
<input type="text" ng-model="story.title" id="title" required/>
</div>
<div>
<label for="firstName">Full Name</label>
<input type="text" ng-model="story.fullname" id="fullname" required/>
</div>
<div ng-repeat="story in items">
<label>Tag {{$index+1}}:</label>
<input type="text" ng-model="story.tag" required/>
</div> <a ng-click="add()">Add Tags</a>
<button id="save" class="btn btn-primary">Submit Story</button>
</form>
<div ng-repeat="test in items">
<label>Tag {{$index+1}}: {{test.tag}}</label>
</div>
</div>
</div>
The NoteController:
function NoteCtrl($scope) {
$scope.story = {};
$scope.items = [];
$scope.story.tag = $scope.items;
$scope.add = function () {
$scope.items.push({
inlineChecked: false,
tag: "",
questionPlaceholder: "foo",
text: ""
});
console.log($scope.story);
};
}
I've got this code:
factory
app.factory('Items', function($firebase,FIREBASE_URL) {
var ref = new Firebase(FIREBASE_URL);
var items = $firebase(ref.child('items')).$asArray();
var Item = {
all: function () {
return items;
},
create: function (item) {
return items.$add(item);
},
get: function (itemId) {
return $firebase(ref.child('items').child(itemId)).$asObject();
},
update: function (itemId, item) {
return $firebase(ref.child('items').child(itemId)).update(item);
},
delete: function (item) {
return items.$remove(item);
}
};
return Item;
});
route
app.config(function($stateProvider) {
$stateProvider
.state('items_update', {
url: '/items/update/:id',
templateUrl: 'views/items/form.html',
controller:'ItemsUpdateController',
resolve:{
item:function(Items,$stateParams){
return Items.get($stateParams.id);
}
}
})
});
controller
app.controller('ItemsUpdateController', function ($scope, item, $state) {
$scope.item = item;
console.log($scope.item.url);
$scope.add = function() {
Items.update($scope.item).then(function () {
$state.transitionTo('items');
});
}
});
why console.log($scope.item.url); give me undefined ?
but in the view I've got all the data
html
<form class="form-horizontal" role="form" name="form" data-ng-submit="add()">
<div class="form-group">
<input type="text" name="title" tabindex="1" class="form-control" placeholder="{{ 'items.form.title' | translate }}" data-ng-model="item.title" required="required" data-ng-minlength="3" data-ng-maxlength="25" user-feedback />
</div>
<div class="form-group">
<input type="text" name="ingredients" tabindex="2" class="form-control" placeholder="{{ 'items.form.ingredients' | translate }}" data-ng-model="item.ingredients" required="required" ng-pattern="/^\w(\s*,?\s*\w)*$/" user-feedback />
</div>
<div class="form-group">
<input type="text" name="price" tabindex="3" class="form-control" placeholder="{{ 'items.form.price' | translate }}" data-ng-model="item.price" required="required" data-smart-float user-feedback />
</div>
<div class="form-group">
<button type="button" tabindex="4" class="btn btn-default btn-lg" item="item" data-uploader>{{ 'items.form.upload' | translate }}</button>
<input type="text" name="url" style="display:none;" required="required" data-ng-model="item.url" />
</div>
<div class="form-group form-no-required clearfix">
<div class="pull-right">
<button type="submit" tabindex="5" class="btn btn-primary" data-ng-disabled="form.$invalid">{{ 'items.form.submit' | translate }}</button>
</div>
</div>
</form>
ENDS UP
as in the #Frank van Puffelen comment
I worked it out with:
app.controller('ItemsUpdateController', function($scope, item, $state) {
item.$loaded().then(function(data) {
$scope.item = data;
console.log($scope.item.url);
});
$scope.add = function() {
Items.update($scope.item).then(function() {
$state.transitionTo('items');
});
}
});
This is because by the time your console.log($scope.item.url); runs, the data hasn't been loaded from Firebase yet. Angular listens for a notification from Firebase/AngularFire to know when the data has loaded and then updates the view.
Also see angularfire - why can't I loop over array returned by $asArray? and Trying to get child records from Firebase.
template code
<script type="text/template" id="test-template">
<section>
<form id="<%= pid %>">
<div class="row">
<div class="span16">
<p>
<input type="radio" checked name="text-align" id="" value="tal" />
<span>标题靠左</span>
<input type="radio" name="text-align" id="" value="tac" />
<span>标题居中</span>
<input type="radio" name="text-align" id="" value="tar" />
<span>标题靠右</span>
</p>
</div>
</div>
<div class="row">
<div class="span16">
<p><input type="text" name="title" class="span10" placeholder="标题" value="<%= title %>" /></p>
<p><textarea name="content" class="span14" placeholder="内容" rows="10"><%= content %></textarea></p>
</div>
</div>
<div class="row">
<div class="span8">
<p><input type="text" name="data-x" placeholder="X 轴" value="<%= data_x %>" /></p>
<p><input type="text" name="data-y" placeholder="Y 轴" value="<%= data_y %>" /></p>
<p><input type="text" name="data-z" placeholder="Z 轴" value="<%= data_z %>" /></p>
</div>
<div class="span8">
<p><input type="text" name="data-rotate-x" placeholder="X 轴旋转" value="<%= data_rotate_x %>" /></p>
<p><input type="text" name="data-rotate-y" placeholder="Y 轴旋转" value="<%= data_rotate_y %>" /></p>
<p><input type="text" name="data-rotate-z" placeholder="Z 轴旋转" value="<%= data_rotate_z %>" /></p>
</div>
</div>
<div class="row">
<div class="span8">
<p><input type="text" name="data-scale" placeholder="缩放" value="<%= data_scale %>" /></p>
</div>
<div class="span8">
<p><input type="text" name="data-rotate" placeholder="旋转" value="<%= data_rotate %>" /></p>
</div>
</div>
<div class="row">
<div class="span16">
<input type="hidden" value="<%= title_align %>" />
<input type="submit" class="btn" value="提交" />
</div>
</div>
</form>
</section>
</script>
(function($) {
window.Step = Backbone.Model.extend({});
window.Steps = Backbone.Collection.extend({
model: Step,
url: MyAjax.ajaxurl + "?action=query-homepage-step",
initialize: function() {
this.fetch();
}
});
window.StepListView = Backbone.View.extend({
el: $('#steplist'),
initialize: function() {
this.model.bind("reset", this.render, this);
},
render: function( eventName ) {
_.each( this.model.models, function( step ) {
$( this.el ).append( new StepView({ model: step }).render().el );
}, this );
return this;
}
});
window.StepView = Backbone.View.extend({
template: _.template( $('#test-template').html() ),
initialize: function() {
this.model.bind( 'change', this.render, this );
},
render: function( eventName ) {
$( this.el ).html( this.template( this.model.toJSON() ) );
return this;
}
});
window. AppRouter = Backbone.Router.extend({
routes: {
"": "init"
},
init: function() {
console.log('init');
this.steps = new Steps();
this.stepView = new StepView({ model: this.steps });
this.steps.fetch();
}
});
})(jQuery);
what's wrong with it ?
i already make a template called $('#test-template') in page and pass all <%= var %> correctly?
Uncaught TypeError: Cannot call method 'replace' of null
b.templateunderscore-min.js:28
(anonymous function)stepmakerapp.js:27
(anonymous function)
sandbox is here http://zhanghong.sinaapp.com/make-homepage
Change the include files from header to body... some thing like the below,
<body>
<script src="lib/jquery-1.7.1.min.js" type="text/javascript"></script>
<script src="lib/underscore-min.js" type="text/javascript"></script>
<script src="lib/backbone-min.js" type="text/javascript"></script>
</body>
This works for me.
More specifically to #Sats' answer, you need to define your templates BEFORE loading all the other JS files. At least that's what fixed it for me :)