event.preventdefault() not working after second render - backbone.js

I'm using brunch to work with backbone and I'm having issues with event.preventdefault(). It works initially, but after a page change it stops working.
I have a view that passes a param to the template and according to that the page is rendered. This page has multiple forms, and loads up one according to the param. All the forms have preventdefault bound to the submit buttons, but for some reason, after I switch forms using one of the nav links, the preventdefault stops working and the form gets posted. Any idea why this is the case? Let me know if you need to see code.
An example of how this happens:
I click 'submit story' nav link and type something and hit submit. I get the js alert and nothing happens. Now I click 'submit poem' and click submit, but this time the form gets posted. If I started off with 'submit poem' it works fine. It also works if I click 'submit poem' and hit refresh before submitting. Weird....
EDIT: Added Code Sample. Template renders acording to the passed in type.
class exports.ClientsSettingsView extends UberView
id: 'settings_view'
className: 'view_container'
events:
'submit #credit_card_form' : 'addCard'
'submit #profile_pic_form' : 'processPicUpload'
'submit #edit_info_form' : 'test'
'click #delete_card' : 'deleteCard'
render: (type="info",status=0) ->
$('.spinner#submit').hide()
#ReadUserInfo()
$(#el).html clientsSettingsTemplate {type,status}
#FadeIn()
#
addCard: (e) ->
e.preventDefault()
$el = $(e.currentTarget)
attrs =
card_number: $el.find('#card_number').val()
card_code: $el.find('#card_code').val()
card_expiration_month: $el.find('#card_expiration_month').val()
card_expiration_year: $el.find('#card_expiration_year').val()
options =
success: (response) ->
alert "Added"
error: (e) ->
alert "Error"
model = new app.models.paymentprofile
model.save attrs, options
console.log attrs

How are you loading the additional forms and submit buttons later on? if you are dynamically pulling them in, your event may no longer be attached. You could try binding your event to the form submit using jquery's live method.
.live()

I had the same problem.
A workaround
is to manually call delegateEvents() after the Backbone.View is added to the DOM.
The issue
I was calling subview.remove() which removes all DOM event listeners (via jQuery.remove) and used that same subview instance later on.
A solution
If a View has to remain active but must be temporary hidden use this.$el.hide() & this.$el.show()
In other situations don't reuse Backbone.View instances, but instantiate new ones.

Related

How to trigger Click event after associated interface has loaded for the first time only?

I want to make sure that a certain interface is loaded and displayed before i can trigger a click event on a button contained in that interface.
I am creating the interface using the following code :
var mainV2 = Ext.create('widget.main', {
renderTo: Ext.getBody(),
hideMode: 'visibility',
//Update
listeners: {
afterrender: function() {
Ext.getCmp('#somebutton').fireEvent('click');
}
}
});
mainV2.show();
And firing the event right under the mentioned code
Ext.getCmp('#idcheckItem').fireEvent('click');
But it seems that the fireEvent is not affecting the button listener's. I was thinking because the call should be synchronous.
My question is how to make sure the mainV2 has loaded before firing the click event on the button only when mainV2 is called and displayed for the first time ?
Thanks for the great help.
You can create an afterRender method in the panels controller.
Here is a fiddle
This fiddle fires a buttons click event after the window is rendered.
Be sure to put the afterRender method in the controller. I ran into some trouble when putting it directly on the panel.

ngDialog returns undefined view

I'm using ngDialog js plugin, to open a view in a modal existing in another view :
I'm in "items" page(view) when I click new group, a popup appears where I can find the "items groups" view to add edit or delete a group.
Plugin is working fine, when I click new group, the popup modal appears but it doesn't return the groups view, it returns undefined.
My laravel project files
app
bootstrap
resources
storage..
I'm calling the template inside : resources/views/GroupsInv
code :
$scope.openNewAddItemForm = function () {
ngDialog.open({template: 'GroupsInv/GroupsInvView', className: 'ngDialog- theme-default', plain: true, scope:$scope});
Problem : popup opens and shows "undefined". I don't know if the problem is the path.
Route working fine :
Route::get('/GroupsInvView', function () {
return view ('GroupsInv/GroupsInvView');

Dynamically add and remove events in angular.js

I'm new to angular.js and still struggling to catch best practices. In this particular case I'm unsure what would be angular way to dynamically add and remove event handlers.
I've created an simplified example that mimic my problem. In this example user can select from one of the items in a list. To select an item, user clicks on button that will display list. Clicking on a list, selection will be changed and list hidden.
But, what I want to do now is enable user to click anywhere on a page to hide list. Using jQuery approach I would add click event handler on body or document that would change view state and hide popup list.
I've created an example on jsfiddle with this approach. My question is: Is this good practice in angular.js? It feels kind of hackish.
Also, please note that I don't want to have a event handler present on document all the time, only when list is displayed.
Using practices described in angular.js guide, I've created directive that should handle the show/hide events.
.directive('toggleListDisplay', function($document) {
return function(scope, element, attr) {
var hideList = function (event) {
scope.listDisplayed = false;
$document.off('click', hideList);
scope.$apply();
};
element.on('click', function(event) {
event.stopPropagation();
scope.listDisplayed = !scope.listDisplayed;
if (scope.listDisplayed) {
$document.on('click', hideList);
} else {
$document.off('click', hideList);
}
scope.$apply();
});
};
});
This directive will add click event handler on element, and will start looking for a click on a document untill list is displayed. When it is not displayed anymore, it will stop watching for click event on document.
Working example can be found on jsfiddle.

How can I make CKEditor update my backing data object when I am looking at Source?

When my users make changes to the edit window it seems like the backing data object is update constantly. However when the user clicks on [SOURCE] and makes changes then it seems there is no update.
I added the following to my code:
ck.on('mode', function () {
$scope.$apply(function () {
ngModel.$setViewValue(ck.getData());
});
});
This senses when the user returns from [SOURCE] to normal view and when that happens it updates my data.
However when the user stays in [SOURCE] view and clicks save on my screen it does not pick up the latest changes. Is there a way I can listen to changes in the [SOURCE] view and then update my backing datastore as these changes are made?
Can you look # https://github.com/esvit/ng-ckeditor
Ready to use Ckeditor Directive
You could always add a "blur" directive and retrieve the data from [SOURCE] on blur...
app.directive('blur', function () {
return function (scope, elem, attrs) {
elem.on('change', function () {
scope.$apply(attrs.blur);
});
};
});
$scope.getCkData = function () {$scope.ckData = ck.getData();};
<textarea id="editor1" name="editor1" blur="getCkData()">Default</textarea>
Now, from looking at CK Editor, when you click the "source" button, a new textarea is overlaid on the editor window. So, you may need to add the blur using a jquery selector.
$('#editor1 > textarea').attr('blur', 'getCkData()');
So, this way whenever someone leaves the source or wysiwyg view, the model gets updated.

How to bind Marionette.ItemView to existing page element, instead of passing in a template?

Our application uses Mustache templates in the index.mustache and makes the initial API call with Symfony instead of using Backbone. This is so the user won't be staring at a blank screen on initial page load.
Now how can we use Marionette afterwards to bind to the rendered page elements in the DOM (so we can manipulate the data and add interactivity), instead of passing a new template?
As far as our research suggests, we need to always pass in a template to Marionette Layout and ItemView, or we get a 'no template error'.
Is there an el property we can use, just like in Backbone?
The other option would be to extend Marionette.View, but it is not advised to do so.
You just should instantiate the view, without rendering.
http://jsfiddle.net/vpetrychuk/PkNTp/
var ItemView = Backbone.Marionette.ItemView.extend({
el : '.content',
events : {
'click' : 'clickHandler'
},
clickHandler : function () {
this.$el.append('clickHandler');
}
});
new ItemView();

Resources