How to change x-editable event order? - javascript

I'm using angularJs and xeditables to create a web application.
In this application, I have several xeditable text following each others and the validation is done when pressing enter or clicking outside:
<div ng-repeat="answer in item.answers track by $index">
<input type="radio" name="{{item.label.text}}"> <span editable-text="answer.text" onshow="onShow()" onhide="onClose()" buttons="no" blur="submit" onbeforesave="validateEditableText($data)">{{answer.text || "Edit this text"}}</span>
</div>
My functions onShow() and onClose() are the following :
$scope.onShow = function() {
alert('onShow');
if($scope.hideMenu == true)
$scope.hideMenu = false;
};
$scope.onClose = function() {
alert('onClose');
if($scope.hideMenu == false)
$scope.hideMenu = true;
};
These functions are just changing a boolean to true.
I use this boolean to stop or not the event propagation (It may sounds weird but I need this functionality).
Here is my function which block the event propagation but it won't be necessary for you to fully understand it for the explications:
$scope.blocEventPropagation = function(event) {
if($scope.selectedItem != null){
if($scope.hideMenu && !$scope.selectedItem.dropDownOpen)
event.stopPropagation();
}
};
Actually the problem I have is, when I click on a xeditable text and then I click directly on another the events don't follow the order I want.
The order is onShow() of the first xeditable text when I click on it, onShow() of the second when I directly click on it before closing the other and onClose() of the first.
Me I'd like onShow() of the first when I click on it, onClose() on the first when I click a second one and onShow() of the second.
At this point read all the documentation of xeditable and I didn't found a solution. I tried to use a time-out to wait the other event but it didn't work.
Do you have an idea to change the event order or to limit the call of a function or even another solution that I didn't think about ?

You can have all elements give a separate contribution in hiding the menu:
<div ng-repeat="answer in item.answers track by $index">
<input type="radio" name="{{item.label.text}}"> <span editable-text="answer.text" onshow="{{$scope.hideMenu[$index] = true;}}" onhide="{{$scope.hideMenu[$index] = false;}}" buttons="no" blur="submit" onbeforesave="validateEditableText($data)">{{answer.text || "Edit this text"}}</span>
</div>
And then, hide it if any element is shown:
<div id="menu" ng-hide="{{$scope.hideMenu.indexOf(true) >= 0}}" />
There may be syntax errors, but I hope it clarifies the point.

Finally I found a solution :
$scope.count = 0;
$scope.onShow = function() {
$scope.count ++;
if($scope.hideMenu == true)
$scope.hideMenu = false;
};
$scope.onClose = function() {
$scope.count --;
if($scope.hideMenu == false && $scope.count == 0)
$scope.hideMenu = true;
};
This solution is very ugly but I really think that with my actual knowledge its the better one in this very specific situation. I tried to find a better one but I couldn't.
Indeed, the previous answer works if we use onShow() and onClose() inside a ng-repeat with the $index. But me I use these two functions at different places in my application so I can't have an index.

Related

Jquery - check if control is NOT currently being edited

I have some code that updates controls on my page using Javascript/Ajax/Json calls.
My only problem is that sometimes the control is updated while the user is actively attempting to change the control.
For example - I will be typing in something, and the Ajax call will execute, replacing what I have typed.
Is this a way in javascript/jquery to say:
If $(this).NotBeingCurrentlyEdited ?
I know about the focus option, but how can I say "Not in focus, not being edited currently?"
You can use document.activeElement to check which element has the focus. If the element you want to change has the focus then skip the update. See example snippet below.
var val = 0;
setInterval(() => {
$('input').each((i, el) => {
if (document.activeElement !== el) {
$(el).val(val);
}
});
val++;
}, 2000);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input id="1">
<input id="2">
The way I would approach it is using a timer to determine if the textbox has recently been changed by the user. You could combine this with checking the control's focus as well once an Ajax request is received. You can either disregard updates to that field entirely when TextBoxIsBeingEdited = true or store the updates somewhere to push once the timer ticks.
var TextBoxIsBeingEdited = false;
function TextBoxEdited(){
if(TextBoxIsBeingEdited === false){
document.getElementById("TextBoxStatus").innerText = "Editing";
TextBoxIsBeingEdited = true;
setTimeout(ResetTextBoxEdited, 2000);
}
}
function ResetTextBoxEdited(){
document.getElementById("TextBoxStatus").innerText = "Not Being Edited";
TextBoxIsBeingEdited = false;
}
<input type="text" id="TextBox" oninput="TextBoxEdited()">
<br><br>
<div id="TextBoxStatus">
Not Being Edited
</div>

Click event undo

I'm working on my very first site and have a problem with click event.
here is my website (it's unfinished): https://pawcio93.github.io/PortfolioSinglePage/
The problem is that #cancel does not work (function run after click, I checked it with alert, but click event does not undo itself at all. I also try to use .on .off method but with same result. If it's making something wrong or I can't use those methods to undo this 'click' function properly? If not, how should I perform that? Thank in advance for reply I will try to figure it out myself, waiting for Yours propositions
var chooseHobby = function() {
$(this).addClass('hobbyOnClick').removeClass('hobby firstInLine hobbyImg');
$('.hobbyImg').hide();
$('.hobby').css('display', 'none');
updateHeight2();
var id = this.id;
if (id == 'sport') {
if (document.getElementById("gym")) {
return;
} else {
$('#sport').append('<img id="runmaggedon" src="img/runmaggedon.jpg" alt="runmaggedon" />');
$('#sport').append('<img id="gym" src="img/gym.jpg" alt="gym" />');
$('#sport').append('<div class="sportText">\n\
<p>Runmaggedon is my hobby for over a year, it is challenging, hard and the people and athmosphere there is just great. For now my best distance is 24 km in mountain terrain, but it was not my last word! </p>\n\
\n\
</div>');
$('#sport').append('<div class="sportText"><p>Working out is something that I&#39m doing since studies. It is became the part of my daily routine, I love to work with my body and see physical ad power progress. Gym also help with self-discipline and well-being </p></div>');
$('#sport').append('<div id="cancel"><p>CANCEL</p></div>');
}
} else if (id == 'travel') {
alert("travel");
} else if (id == 'objectivism') {
alert("objectivism");
} else if (id == 'engineering') {
alert("engineering");
} else if (id == 'programming') {
alert("programming");
} else if (id == 'economy') {
alert("economy");
}
$("#cancel").bind("click", function() {
alert("function start");
$(".hobby").unbind("click", chooseHobby);
});
};
$(document).ready(function() {
$(".hobby").bind('click', chooseHobby);
});
A click is an event. It happens milliseconds (quite instantly) after a user click.
You can't "undo" it.
To that event, you can register a function to execute. Now to "undo" the changes made by such a function, you have to store the previous relevant states/values. And using another click event, you can give the impression of an undo.
Here is a really simple example which only changes a <h1> text.
// Store initial text.
var previousH1state = $("h1").text();
// Modify
$("#modify").on("click",function(){
$("h1").text("I'm modified!");
});
// Undo
$("#undo").on("click",function(){
$("h1").text(previousH1state); // Notice the stored text is used here.
});
// De-register functions tied to click events from the modify/Undo buttons.
$("#off").on("click",function(){
$("#modify, #undo").off("click");
console.log("Modify and Undo buttons are not working anymore");
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<h1>I'm unchanged.</h1>
<button id="modify">Modify the header above</button>
<button id="undo">Undo the modification</button><br>
<br>
<button id="off">Use .off()</button>
.off() is used to de-register a function from the event on an element. That is something else...
More on events.

Angular ng-if not responding as expected

I have li elements that have an ng-if statement that is tied to a checkbox. If I physically check the checkbox, the ng-if responds as expected. However, if I check or uncheck the checkbox via JavaScript, the checkboxes get checked or unchecked as expected, but the ng-if does not respond. Is this working as it should? Is there a better way to do this?
Here are my code samples: "[]" = "<>"
HTML - Part 1
[li id="homebutton" ng-if="homechecked != true" onclick="homeclicked()"][a ng-href="/"][img src="images\Neck01Home.png" alt="Home" /][/a]
[li id="thebandbutton" ng-if="homechecked===true" onclick="thebandclicked()"][a ng-href="/theband/"][img src="images\Neck01TheBand.png" alt="The Band" /][/a]
HTML - Part 2
[label class="menucontroller"]Home2: [input class="menucontroller" id="homecb" type="checkbox" ng-model="homechecked" ng-init="homechecked=true" /][/label][br /]
[label class="menucontroller"]TheBand2: [input class="menucontroller" id="bandcb" type="checkbox" ng-model="thebandchecked" /][/labe][
[label class="menucontroller"]Gallery2: [input class="menucontroller" id="gallerycb" type="checkbox" ng-model="gallerychecked" /][/label][br /]
JavaScript:
window.onload = function () {
}
function homeclicked() {
document.getElementById('homecb').checked = true;
document.getElementById('bandcb').checked = false;
document.getElementById('gallerycb').checked = false;
}
function thebandclicked() {
document.getElementById('homecb').checked = false;
document.getElementById('bandcb').checked = true;
document.getElementById('gallerycb').checked = false;
}
function galleryclicked() {
document.getElementById('homecb').checked = false;
document.getElementById('bandcb').checked = false;
document.getElementById('gallerycb').checked = true
}
you're doing it wrong, ng-if does not trigger because you only manipulate the checked and unchecked of the check box(using javascript) and not the ng-model, dont try to use javascript to do that, instead do it on your angular controller.
Controller:
$scope.homeclicked = function() {
$scope.homechecked = true;
$scope.thebandchecked = false;
$scope.gallerychecked = false;
};
ng-model on checkbox inputs handles checked and unchecked of it, also there is a native directive https://docs.angularjs.org/api/ng/directive/ngChecked for handling of check and uncheck.
Do it in proper angular way.
Move the functions inside your controller. Call them via ng-click. Let the functions change the scope variables which are bound to check boxes.
<li id="homebutton" ng-if="homechecked != true" ng-click="homeclicked()">
In the mean time inside your scope...
$scope.homeclicked = function {
$scope.homechecked = true;
$scope.thebandchecked = false;
$scope.gallerychecked = false;
}
If you really really want to disregard my advice and go ahead with what you have, which is by the way very bad, you can add this line inside your functions: angular.element(document.getElementById('homecb')).$scope().$apply(); This is again very bad and should totally be avoided.
Use
$scope.$apply();
It will run the digest loop and your ng-if will work as u expect.

Class isn't added in angular

I have an angular function
$scope.show = function(el){
if($scope.steps[el] == true){
$scope.steps[el] = false;
}
else{
$scope.steps = [];
$scope.steps[el] = true;
}
}
When I call It by click this
<span class="" ng-click="show('getDate')">text</span>
Then a class 'shown' adds in this div
<div class="form-block steps second" ng-class="{shown : steps.getDate}">
but I don't get the class when call the fanction in this cod
$(document).on('click', "li", function() {
$scope.show('getDate');
console.log($scope.steps);
});
but in console i get this log
[getDate: true]
LI tag generated with JS by jquery.formstyler http://dimox.name/jquery-form-styler/ from SELECT tag
As #charlietfl stated this is happening due the fact that you updated your DOM outside of the "Angular" world. Thus, resulting of angular not knowing you did such a change.
In order to fix it you should force angular to digest by using the keyword $apply.
Example:
$(document).on('click', "li", function() {
$scope.$apply(function () {
$scope.show('getDate');
});
console.log($scope.steps);
});
Important Note: Most of the time It's poor behavior to use jQuery rather than the AngularJS way.
Thanks for #Bhojendra Nepal for noticing the bug.

JavaScript click has different behavior than manual one

With prototype I'm listening for a click event on several checkboxes. On checkbox click I want to disable all <select> elements. I'm using prototype. So, I have this code:
$$('.silhouette-items input[type="checkbox"]').invoke('observe', 'click', function(event) {
var liItem = this.up('li.item');
if(this.checked) {
alert('checked');
liItem.removeClassName('inactive');
var selectItem = liItem.select('select');
for(i=0;i<selectItem.length;i++) {
selectItem[i].disabled=false;
if (selectItem[i].hasClassName('super-attribute-select')) {
selectItem[i].addClassName('required-entry');
}
}
} else {
alert('unchecked');
liItem.addClassName('inactive');
var selectItem = liItem.select('select');
for(i=0;i<selectItem.length;i++){
selectItem[i].disabled=true;
if (selectItem[i].hasClassName('super-attribute-select')) {
selectItem[i].removeClassName('required-entry');
}
}
}
calculatePrice();
});
When I manually click on the checkbox, everything seems to be fine. All elements are disabled as wanted.
However, I have also this button which on click event it fires one function which fires click event on that checkbox.
In Opera browser it works. In others, not. It's like Opera first (un)check and then executes event. Firefox first fires event, then (un)check element.
I don't know how to fix it.
The HTML:
<ul class="silhouette-items">
<li>
<input type="checkbox" checked="checked" id="include-item-17" class="include-item"/>
<select name="super_attribute[17][147]">(...)</select>
<select name="super_group[17]">(...)</select>
<button type="button" title="button" onclick="addToCart(this, 17)">Add to cart</button>
</li>
<!-- Repeat li few time with another id -->
</ul>
Another JS:
addToCart = function(button, productId) {
inactivateItems(productId);
productAddToCartForm.submit(button);
}
inactivateItems = function(productId) {
$$('.include-item').each(function(element) {
var itemId = element.id.replace(/[a-z-]*/, '');
if (itemId != productId && element.checked) {
simulateClickOnElement(element);
}
if (itemId == productId && !element.checked) {
simulateClickOnElement(element);
}
});
}
simulateClickOnElement = function(linkElement) {
fireEvent(linkElement, 'click');
}
Where fireEvent is a Magento function that triggers an event
Don't bother simulating a onclick if you can get away with not doing so. Having a separate function that can be called from within the event handler and from outside should work in your case.
var handler = function(){
//...
}
var nodeW = $('#node');
handler.call(nodeW);
Of course, this doesn't trigger all onclick handlers there might be but it is simpler so it should work all right. Points to note for when you use .call to call a function:
Whatever you pass as the first parameter is used as the this inside the call. I don't recall exactly what JQuery sets the this too but you should try passing the same thing for consistency.
The other parameters become the actual parameters of the function. In my example I don't pass any since we don't actually use the event object and also since I don't know how to emulate how JQuery creates that object as well.
replacing
fireEvent(linkElement, 'click');
with
linkElement.click();
works in firefox 5 and safari 5.1, so maybe the problem lies in the fireEvent() method.

Categories

Resources