editableText plugin enabling problem - javascript

I've been experimenting with this plugin http://valums.com/edit-in-place/, so far so good... But i ran into this problem. I want to update my page when update or new request to save data is sent but if i update this function(edit-in-place) it will add second set of buttons, third, fourth and so on. How could i tell it that it would update just on that returned data, but not all elements? I have an idea it has to do something with each function of jquerys, but I'm not sure as I'm quite new to jquery. Thanks for any help!

You can give the selector a context, so for example if you're doing this now:
$('.editableText').editableText({
newlinesEnabled: false
});
In your ajax callback, give it a context when calling it in the success or complete method, wherever you're adding elements, like this:
$.ajax({
...options here...
success: function(data) {
$('.editableText', data).editableText({
newlinesEnabled: false
});
//insert the elements somewhere...
}
});
The , data gives it a context (you can see options for $(selector, context) here), this means it's only searching for elements of that class within the returned data/html, not all elements on the page. This should eliminate your repetition issue of it selecting and running the plugin on elements it's already run on.

Related

Dynamically reload elements and read their new attributes in JQuery

I have an Ajax call that returns a piece of html code that is supposed to replace old html code on the page, giving them new attributes. After I successfully dynamically change my elements, I want to run another piece of JS code that reads and uses some of the attributes of the dynamically reloaded elements. However, JS prefers to read the old data (as if it's running synchronously).
The only workaround I've found is to set a timer, but the timer's delay time has to be relatively high (300 ms) to guarantee that it's always done correctly. What is the right way to do this?
Here is a pseudo-code for what I have right now. It works but the 300ms delay time is terrible.
$.post( "ajax/test.html", function( newCode ) {
$("#myDynamicDiv").html(newCode);
setTimeout(function(){
//Use the data that was just stored in #myDynamicDiv
},300);
});
For me I use .promise().done() may be it'll work with you
$("#myDynamicDiv").html(newCode).promise().done(function(){
// your code here
});
Edit: To someone who'll comes here later ..While my code isn't working with Mohasen he find a solution himself .. Please find his answer below
I accepted Mohamed-Yousef's answer, but since that did not include the full answer, here is the full version of what I eventually did:
A JQuery ajax call always returns a "Deferred" object when it's called. You can use this object's "then()" method to run things after the ajax call is finished. Here is the code:
dfrd = $.post( "ajax/test.html", function( newCode ) {
$("#myDynamicDiv").html(newCode);
});
dfrd.then(function(){
//Anything that is here is guaranteed to happen after the Ajax call is done.
});

ExtJS - Overriding the FieldSet xType and adding a function does not seem to work?

I am developing a web application and I want to check if my fieldSet is dirty. The first thing I attempted was fieldSet.isDirty(); but I soon met with an error as the function isDirty() cannot be applied to the fieldSet xType. Wanting to still use an elegant solution, I then wrote an override for the fieldSet. My override looks like:
Ext.define('myApp.override.form.FieldSet', {
override: 'Ext.form.FieldSet',
sampleOverride: function(){
console.log("hi! sample override function entered");
},
checkForDirtyFields: function(){
me = this;
return this.getFields().findBy(function(f){
return f.isDirty();
});
}
});
As you can see, I wrote 2 functions, one as an example, and the other, for checking dirty fields inside the fieldSet. Upon trying to use it in my controller as:
fieldSet.checkForDirtyFields();
fieldSet.sampleOverride();
I am greeted by an error: Uncaught TypeError: fieldSet.sampleOverride is not a function
Am now legitimately confused. I've written overrides for the Panel XType and I am able to use them as intended (for clearing dirty status, for clearing the fields inside a form, etc). However, it seems that I can't make an override function for the fieldset.
Sorry for disappointing. I found a work around. My issue was that I had more than 1 store whose data is shown in a form, separated by fieldSets. The issue lies in saving the data in the page and using isDirty() to check if any changes needs to be committed. Checking for form.isDirty() would return true even if the fieldSet for one store was changed.
What I did was that after doing form.updateRecord(record);, I checked with record.isModified(); to see if there is a change that needs to be committed. If it returns true, I proceed with my store syncing. If it returns false, then the record wasn't modified and I go on with my code.
Now, if you'd really want a function call, I suggest making a controller that takes a fieldSet/fieldContainer, go through the elements, and check the elements if any of those return false when checked with dirty.

How to animate unchanged ng-repeat with AngularJS

I have a template that looks like this:
<p ng-repeat="item in myobj.items" class="toAnimate">{{item}}</p>
and I would like to use the animate module do a jQueryUI addClass/removeClass animation on the element using the JavaScript method described in the docs:
ngModule.animation('.toAnimate', function() {
return {
enter: function(element) {
element.addClass('pulse').removeClass('pulse', 2000);
}
};
});
This works beautifully, but the problem is that, since I want to use the p.toAnimate element to display status messages, it will not change the content according to angular.
To break it down a little further, say I have a name field. When I click Save the message Name was saved successfully. is displayed. Now if I modify the name and click save again, assuming the save was successful, the message should be re-displayed to give the user feedback of the newly edited name. The pulse does not happen, however, because the items in myobj.items didn't technically change.
I realize that I could remove the item after a period of time (and that is probably the route I will take to implement the real solution), but I'm still interested to see if this sort of thing can be done using AngularJS.
What I want to do is register with angular that the message should be treated as new even though it is not. Is there any way to do this?
A fiddle to go along with this: http://jsfiddle.net/Jw3AT/
UPDATE
There is a problem with the $scope.$$phase approach in my answer, so I'm still looking for the "right" way to do this. Basically, $scope.$$phase is always returning $digest, which causes the conditional to fail. Removing the conditional gives the correct result in the interface, but throws a $rootScope:inprog.
One solution I found is to add a $apply in the middle of the controller function:
$scope.updateThingy = function () {
$scope.myobj.items = [];
if (!$scope.$$phase) {
$scope.$apply();
}
$scope.myobj.items = ['Your name was updated.'];
};
Updated fiddle: http://jsfiddle.net/744Rv/
May not be the best way, but it's an answer.

jQuery Plugin - Public method - Data only targeting one element

I'm trying to write a plugin that will select multiple elements and then apply some private methods to them (see code below). Then I also want to give the user the ability to trigger the activation of the plugin's methods manually with a .activate() function.
Here is my code :
MARKUP : https://github.com/simonwalsh/jquery.imagepox/blob/master/demo/index.html
JS : https://github.com/simonwalsh/jquery.imagepox/blob/master/dist/jquery.imagepox.js
Basically, when I select multiple items and then try to use the manual activation like so :
$(".pox-wrapper").imagepox({ // NOTE: selects two elements
manualActivation: true
});
var manual = $(".pox-wrapper").data('imagepox');
setTimeout(function(){
manual.activate();
}, 5000);
It will only apply the activate() method to the first element in the query...
This is my first jQuery plugin and I've been able to handle everything so far but I'm not sure about this one or even if it is the right way to effectively call a public method. I also tried using a custom event with an event listener in the plugin but it still only applies the methods on the first element in the page.
Thanks in advance :)
its not your plugin's fault. data does not work like that, it doesnt know how to return data from a collection of elements. Because think about it, each element in the collection contains its own data object!
So when you call data on a collection, it returns the data from the first one. The quick solution would be to change the innards of the setTimeout into a loop over all the elements in the set and call activate on them.
setTimeout(function(){
$(".pox-wrapper").each(function(){
$(this).data('imagepox').activate();
})
}, 5000);
It seems to me that you want to add functions to collections of jquery objects. This is the usecase of a jquery plugin. You can create a lightweight one like this:
$.fn.imagepox.activate = function(){ //do this after you create your plugin!
return this.each(function(){
var $this = $(this);
var data = $this.data('imagepox');
if(data){
data.activate();
}
});
};
now you can call it like this:
$(".pox-wrapper").imagepox.activate()

jQuery recursion

I have a problem with my code, some code does not work when I call recursive call of same function inside it. It has to be something with myGalleria = Galleria.get(0);, but I have no idea how to make it all work.
Document Ready (just to show when I call function for the first time, everything works fine for first time)
$(document).ready(function(){
$.getJSON('getImages.php', {
cat: "123"
}, function(imgData){
createGallery(imgData);
});
});
Now function itself, note that when I click on .galleria-menuButtons span that calls same function nothing is working, well galleria itself is creating, but nothing else.
function createGallery(imgData){
$("#gallery").galleria({
image_margin: 30,
clicknext: true,
transition: "fade",
dataSource: imgData
});
myGalleria = Galleria.get(0); // I don't think this works after recursive call
// Adding menu and menu buttons
myGalleria.addElement("menu").appendChild("container", "menu");
myGalleria.addElement("menuButtons").appendChild("menu", "menuButtons");
$.ajax({
url: "menuButtons.php",
success: function(data){
myGalleria.$("menuButtons").html(data);
}
});
// Menu button click events
$('.galleria-menuButtons span').live('click', function(){
alert(this.id);
// Getting jSon data
$.getJSON('getImages.php', {
cat: this.id
}, function(imgData) {
alert(imgData);
createGallery(imgData); // <- Recursive call
});
});
}
I have similar function on window.resize and it also does not work after recursive call.
$(window).resize(function(){
$(".galleria-container").css("width", $(window).width());
$(".galleria-container").css("height", $(window).height());
galleriaRescale = Galleria.get(0);
galleriaRescale.rescale(); // <- this is not working either
//sizeBG();
});
FYI - this isn't actually recursion in the traditional sense because you're calling createGallery from a click handler which launches a JSON request which then calls createGallery when that succeeds, both of which will occur after the previous call to createGallery finishes.
But you do have surviving function closures which could be confusing things or causing problems. One guess is that you may want to make sure that things you expect to be local variables (like myGalleria have a var in front of them so they really are local variables and not variables that might be scoped to a higher level and be influenced by a previous incarnation of this call or be influencing an earlier call that hasn't yet completed.
var myGalleria = Galleria.get(0);
Then, assuming imgData is some sort of data structure like an array or object, you have to make sure that there's either only one global version of that data structure that never changes or that each call of createGallery has the appropriate separate copy of that data structure. If it's getting changed along the way, then subsequent calls to createGallery may not be getting the data they want. If it's a read-only data structure (you don't change it), then you're probably OK on that one.
OK, let's talk through the pseudo code for what this does.
On page ready, you get some JSON image data.
When that succeeds, you call createGallery with that image data.
The createGallery call does some sort of operation in the DOM (perhaps an animation)
It then calls: myGalleria = Galleria.get(0); Because there is no var in front of myGalleria, this is a global variable declaration (bad news for recursion and closures)
You then use the myGalleria data structure to make some changes to the DOM (adding menus and menu items).
You then add a .live click handler on a pretty generic set of CSS classes (it's possible you have added this click handler more than once here).
You then fetch some JSON image data again.
When that image data is fetched, you start the whole process over again by called createGallery.
Summary
The two potential problems I see are that myGalleria is not a local variable and probably should be and you may be adding duplicate click handlers.
If neither of these fully solve the issue, then we probably need more information about what Galleria.get(0) is doing.
FYI, the resize clickHandler looks like it may have the same issue with not using var to make your variable declaration a local variable.
Round 2
OK, here are some more observations.
When you add the menu and menu buttons with this block of code, you aren't providing any unique identifiers to either the addElement or appendChild functions (you're providing "menu" and "menuButtons" to both). As such, I don't know how you can uniquely hook up to them in the subsequent click event. As far as your code looks, all the menu items look identical and none have unique state. I don't know the Galleria code, but I assume somebody has to make unique identifiers for these new items so that you can uniquely identify them in your subsequent click handler.
// Adding menu and menu buttons
myGalleria.addElement("menu").appendChild("container", "menu");
myGalleria.addElement("menuButtons").appendChild("menu", "menuButtons");
When you set up a click handler to presumably handle the clicks for just these menu items, you are using the exact same CSS selector every time so there's no way that this click handler is going to be uniquely assigned to just the newly create menu items (which is what I assume you want). I don't know the Galleria code, but I assume that you should create some sort of unique ID that you pass into addElement and appendChild for the newly created menu items and then reference that unique identifier when you install the click handler. Likewise, this function needs to uniquely target just the menu buttons you created by using unique identifiers myGalleria.$("menuButtons").html(data);
Lastly, I'd suggest you change the name of one of your variables just to avoid confusion. In your click handler, change the three occurrences of imgData to just data so there can be no confusion about closures and the value of imgData.
Round 3
Ultimately one of the fixes was this (embedded in the comments):
I think it might work if you just only install the .live click handler once outside the createGallery function rather than call it each time. Since it's .live it will automatically work for all future buttons you create so you should only call it once. I'd suggest putting it in the $(document).ready function block.

Categories

Resources