I have a simple page that contains a 3 step wizard. Basically, the user fills out a textbox, clicks next, which loads the next form field.
I have setup all the HTML inside a template and use that template in a backbone view.
The problem is, backbone isn't rendering the HTML inside the template. I just get a blank screen.
Here is my template:
<script type="text/template" id="assessmentTitleTemplate">
<div id="titleDiv">
<label for="title">Title:</label> <input type="text" />
</div>
<div id="choicesDiv" style="display: none;">
<label for="choices">Choices:</label><input type="text" />
</div>
<div id="typeDiv" style="display: none;">
<label for="types">Types:</label>
<select name="type">
<option>red</option>
<option>blue</option>
<option>green</option>
</select>
</div>
<div id="directionControl">
<input type="button" value="Prev" /> <input type="button" value="Next" />
</div>
</script>
This is my backbone javascript code:
"use strict";
var titleView = Backbone.View.extend({
tagName: 'div',
className: 'title',
template: _.template($('#assessmentTitleTemplate').html()),
events: {
'click .next': 'saveProceedNext',
'click .prev': 'ProceedPrev'
},
initialize: function () {
this.render;
},
render: function () {
this.$el.html(this.template(this.model.toJSON()));
return this;
},
saveProceedNext: function() {
this.$('#titleDiv').hide();
this.$('#choicesDiv').show();
},
ProceedPrev: function() {
}
});
Your code is correct, but you're missing a couple of parens in your initialize body:
initialize : function () {
this.render(); // it was this.render; before
}
Your code isn't invoking the function.
Also, you're missing class tags for your buttons, or else they won't work when clicked. Adding this will make them work:
<input type="button" value="Prev" class="prev" /> <input type="button" value="Next" class="next" />
Check this JSFiddle.
Related
I'm trying to get the radio value button value from ng-dialog but it always got undefined.
Here is the dialog template:
<script type="text/ng-template" id="flag-reasons.html">
<div style="padding:10px;">
<span>
What's wrong ?
</span>
<div class="form-group" ng-repeat="flagreason in flagreasons">
<input type="radio" ng-model="fr" name="frname" value="{{flagreason.id}}"> {{flagreason.title}}
</div>
<div class="form-group">
<button type="button" ng-click="validFlag()">
Valider
</button>
</div>
</div>
</script>
Here is the partial js where I start with the dialog:
$scope.openFlag = function(){
$scope.dialog = ngDialog.open({ template: 'flag-reasons.html',
className: 'ngdialog-theme-default', scope: $scope });
$scope.validFlag = function(){
console.log($scope.fr);
}
}
I have tried ng-value as below:
<input type="radio" ng-model="fr" name="frname" ng-value="flagreason.id"> {{flagreason.title}}
but it still got undefined
Notice that it works when I directly set the value of the radio button like:
<input type="radio" ng-model="fr" name="frname" value="5"> {{flagreason.title}}
The issue is with ngmodel that's not getting update. You have to initialise ngmodel first in the template.
flag-reasons.html
<script type="text/ng-template" id="flag-reasons.html">
<div style="padding:10px;">
<span>
What's wrong ?
</span>
<div class="form-group" ng-repeat="flagreason in flagreasons">
<input type="radio" ng-model="cb.fr" name="frname" value="{{flagreason.id}}">{{flagreason.id}} - {{flagreason.title}}
</div>
<div class="form-group">
<button type="button" ng-click="validFlag()">
Valider
</button>
</div>
</div>
</script>
Controller
angular.module("app", ['ngDialog'])
.controller('Ctrl',function ($scope, ngDialog) {
'use strict';
$scope.cb = {};
$scope.flagreasons = [
{id: 1, title: 'title1'},
{id: 2, title: 'title2'},
{id: 3, title: 'title3'}
];
$scope.openFlag = function(){
$scope.dialog = ngDialog.open({ template: 'flag-reasons.html',
className: 'ngdialog-theme-default', scope: $scope });
$scope.validFlag = function(){
console.log($scope.fr);
}
}
$scope.$watch('cb.fr', function (v) {
console.log(v);
});
});
Working Fiddle: JSFiddle
This is my directive code:
'use strict';
demo.directive('myModal', function($parse) {
return {
restrict: 'A',
transclude: true,
scope: '#',
template: '<div ng-transclude><h4>Please enter value</h4></div>'
}
});
Usage is as follows:
<!-- myModal directive -->
<div my-modal>
<input type="text" ng-model="myTest" />
<input type="button" ng-click="getMyTest()" value="Get Value" />
</div>
And my main controller, which wraps the whole application, includes this:
demo.controller('MainCtrl', function($scope) {
$scope.getMyTest = function(){
alert($scope.myTest);
}
});
Any ideas why can't I access myTest?
JsFiddle: http://jsfiddle.net/sZZEt/679/
You should use the dot-notation:
demo.controller('MainCtrl', function($scope) {
$scope.data = {};
$scope.getMyTest = function(){
alert($scope.data.myTest);
}
});
and
<div my-modal>
<input type="text" ng-model="data.myTest" />
<input type="button" ng-click="getMyTest()" value="Get Value" />
</div>
JSFIDDLE
Transclusion creates a child scope, that's why you should use the dot-notation for ng-model.
try this. add directive to model element.
<div>
<input my-modal type="text" ng-model="myTest" />
<input type="button" ng-click="getMyTest()" value="Get Value" />
</div>
Using AngularJS ngDialog.
Expecting that the CSS in the document is applied to the ngDialog, but it hwas not applied.
Code:
<script type="text/ng-template" id="attach_account_template">
<div id="attach_account_div" ng-controller="Opportunity_Controller" style="width:250px">
<input type="text" class="form-control" id="account_name" style="width:200px;height:35px" />
<input id="btn_account" type="button" style="margin-left:10px;height:35px;width:50px" value="GO" />
</div>
</script>
$scope.attach_account = function () {
//attach_account_template
ngDialog.open({ template: 'attach_account_template', scope: $scope });
};
I am trying to modify a form in a view by means of a button in my directive's template (template is in another file), this is for a basic CRUD where each item has a delete/edit button.
In order to avoid replicating the form I decided to that on edit's click a function would send the item to the controller in questions in order to be updated with the new information.
But I've been having troubles making the connection, so far I tried changing $root, to $rootScope back and forth and using , $broadcast or $emit.
So how can I send the function onChange my item's information based on the template's button click?
Template:
<strong>{{item.type}}</strong> {{item.description}}
<div class="material-switch pull-right">
<button type="button" class="btn btn-warning btn-circle" ng-show="item.editable" ng-click="onChange()">
<span class="glyphicon glyphicon-edit" ></span>
</button>
<button type="button" class="btn btn-danger btn-circle" ng-controller="View1Ctrl" ng-show="item.editable" ng-click="EliminarItem(item)">
<span class="glyphicon glyphicon-minus" ></span>
</button>
<input ng-model="item.isDone"
id="someSwitchOptionDefault{{itemIndex}}"
name="someSwitchOption001{{itemIndex}}"
type="checkbox" />
<label for="someSwitchOptionDefault{{itemIndex}}" class="label-info"></label>
</div>
Directive:
'use strict';
angular.module('myApp.items.directive', [])
.directive('itemSwitch', [ function() {
return {
restrict: 'A',
scope: {
item: '=',
itemIndex: "="
},
templateUrl: 'templates/itemSwitchTemplate.html',
link : function($scope){
$scope.$broadcast('onChange', item);
}
}
}]);
Controller
.controller('View1Ctrl', ['$scope','itemsService',function($scope,itemsService) {
$scope.items = itemsService.getItems();
$scope.classMap = {GROCERIES:"success",CAR:"danger",UNIVERSITY:"warning",PAYMENTS:"info"};
$scope.newItem = {};
$scope.$on('onChange', function(event, args) {
if ($scope.btnEdit) {
$scope.newItem = args;
} else {
$scope.newItem = {};
}
});
$scope.enableEdit = function (item) {
item.editable = true;
};
$scope.disableEdit = function (item) {
item.editable = false;
};
}]);
View
<div class="col-xs-12">
<div ng-model="currentItem" ng-repeat="item in items" item-switch item="item" item-index="$index" class="notice notice-{{classMap[item.type]}}" ng-mouseover="enableEdit(item)" ng-mouseleave="disableEdit(item)">
</div>
<!-- FORMULARIO -->
<form name = "myForm" class="form-horizontal">
<fieldset>
<div id="legend">
<legend class="">Task</legend>
</div>
<div class="control-group">
<!-- Name-->
<label class="control-label">Name</label>
<div class="controls">
<input type="text" name="itemName" ng-model="newItem.name" placeholder="Task Name" class="input-xlarge" ng-required="true" >
<p class="help-block"></p>
</div>
</div>
<div class="control-group">
<!-- Description -->
<label class="control-label">Description</label>
<div class="controls" >
<input type="text" ng-model="newItem.description" placeholder="Task Description" class="input-xlarge">
<p class="help-block"></p>
</div>
</div>
<div class="control-group">
<!-- Button -->
<div class="controls">
<a class="btn icon-btn btn-success" ng-disabled="myForm.$invalid" ng-click="addOrSaveItem()">
<span class="glyphicon btn-glyphicon glyphicon-save img-circle text-success"></span>Save</a>
</div>
</div>
</fieldset>
</form>
</div>
FiddleJS
Look nd Feel
Using "onChange" as an event name is a poor choice as it is likely to conflict with other events with that name. My recommendation is to use the directive's name as part of the event name.
In your directive
angular.module('myApp.items.directive', [])
.directive('itemSwitch', function() {
return {
restrict: 'A',
scope: {
item: '=',
itemIndex: "="
},
template: '<button ng-click="doIt()">Do It</button>',
link : function(scope){
scope.doIt = function() {
scope.$emit('itemSwitch.doIt', scope.item, scope.itemIndex);
};
}
}
});
In your controller
$scope.doItItems = [];
$scope.$on("itemSwitch.doIt", function(item, itemIndex) {
doItItems.push(item);
});
In this example, on each click of the Do It button, an item is pushed to the doItItems list.
In your itemSwitch directive, you can do
$rootScope.$broadcast('onChange', item);
And then you can pick it up in any scope that is listening (in this case, your controller), with
$scope.$on('onChange', function(event, args) { ... }
This works because $broadcast moves downward from parent to children, while $emit moves upward from child to parents.
So for example, $rootScope.$emit would only be picked up by $rootScope.$on since $rootScope has no parents, while $scope.$broadcast would only be available to that scope's children and not to $rootScope.$on, since $rootScope is not a child of $scope
//I am using template in view
App.Backbone.UserView = Backbone.View.extend({
tagName: 'li',
className: 'pp-entry group',
template :_.template('<img src="i/pp-pic-8.png" class="pp-pic" alt="" />),
templatedetails:_.template('`<div style="display:none"><div id="pp-details-<%=username%>" class="pp-details"><div class="cta clear"><input type="button" name="" value="Add to my Wallet" class="mar-right-10 addtowallet" /><input type="button" class="mar-right-10 addtogib" name="" value="Add to gib as link" /><input type="button" name="" value="Close" onclick="$.fancybox.close()" /></div></div><.div>'`)
//Here is the click event defined
events:{
"click .addtowallet":"addlinktowallet",
"click .addtogib":"addasgiblink"
},
//Render contents
render: function() {
$(this.el).html(this.template(this.model.toJSON()));
$(this.el).attr('id', 'pp-'+this.model.get('username')); //This is used to set the id for the "li" tag
$('#pp-'+this.model.get('username')).append(this.templatedetails(this.model.toJSON())); //appending to the template
},
//But when i am defining the function the click event does not get triggered
addasgiblink: function(){
alert("gib button clicked");
},
addlinktowallet: function(){
alert("wallet button clicked");
}
});
The question is when i click on the pic as rendered from template a fancybox popup opens where templatedetails is rendered but when i click on the buttons in the popup it does not get triggered. Why the click function is not working?
The HTML that is generated after rendering is
<li id="pp-bikram" class="pp-entry group">
<img class="pp-pic" alt="" src="i/pp-pic-8.png">
<div style="display:none">
<div id="pp-details-bikram" class="pp-details">
<div class="cta clear">
<input class="mar-right-10 addtowallet" type="button" value="Add to my Wallet" name="">
<input class="mar-right-10 addtogib" type="button" value="Add to gib as link" name="">
<input type="button" onclick="$.fancybox.close()" value="Close" name="">
</div>
</div>
</div>
</li>
Till this point everything is working fine but i am not getting why the click event is not not working. Please suggest me some solution.
This cannot work because fancybox is not opening your content directly but its "clonning" it into its own container $('#fancybox-content').
Nice solution i think is possible by rebinding this container as Backbone.View.$el so you'll have Backbone.events{} working uppon that:
window.FancyboxView = Backbone.View.extend({
events: {
click: 'handleClick'
},
initialize:function () {
this.$trigger = this.$el.find('a.trigger');
this.$trigger.fancybox({
onComplete:$.proxy(function () {
this.setElement($('#fancybox-content')[0]);
}, this)
});
},
handleClick:function (e) {
e.preventDefault();
console.log('woala!')
}
});
In your code while executing this line
$('#pp-'+this.model.get('username'))
that element wont be available in the dom. So what you have to do is
$(this.el).append(this.templatedetails({// Your json}))
As per my observation both this.el and $('#pp-'+this.model.get('username')) are the same the li tag. So refer it as $(this.el). Please let me know if it works
Please update the code as below.
events:{
"click .addtowallet":"addlinktowallet",
"click .addtogib":"addasgiblink"
"click .fancybox":"fancyBoxClose"
},
fancyBoxClose : function(){
$.fancybox.close()
}
templatedetails:_.template('`<div style="display:none"><div id="pp-details-<%=username%>" class="pp-details"><div class="cta clear"><input type="button" name="" value="Add to my Wallet" class="mar-right-10 addtowallet" /><input type="button" class="mar-right-10 addtogib" name="" value="Add to gib as link" /><input type="button" name="" value="Close" class="fancybox" /></div></div><.div>'`)