in my application i post data to the server via ajax, while data is being posted to the server i want to be able to show the user that something is indeed happening, now a simple way to do this will be to display a loading gif. What i actually want to do is change the state of the button that was clicked. I have 4 classes in my css:
btn-ready-state
btn-working-state
btn-completed-state
btn-failed-state
Now each button has a class of btn-ready-state when you click the button the class changes to btn-working-state where the text of the button changes to "working" and a small loading icon appears inside the button. When the operation is done successfully it switches to btn-completed-state if it fails then btn-failed-state. Now i have been able to do this in my code with jquery but the code is so messy and untidy and doesn't work properly with angular. I have been told i can use directives to achieve this but since i am new to angular i am confused as to how to implement this with directives, i do know what a directive is and how to make one, my issue here is the implementation of this particular feature. This is how i did it with jquery:
<script type="text/javascript">
$(document).ready(function() {
var $loading = $('#loading');
$loading.on("change", function(){ //bind() for older jquery version
var index = parseInt($('#loading').val());
var done = parseInt($('#done').val());
if (done === 0) {
$('.btn.ticket:eq(' + [index] + ')').removeClass('btn-ready-state');
$('.btn.ticket:eq(' + [index] + ')').addClass('btn-working-state');
$('.btn.ticket:eq(' + [index] + ')').find('.text').text('Working..');
$('.btn.ticket:eq(' + [index] + ')').find('.state').addClass('loading');
$('.btn.ticket:eq(' + [index] + ')').find('i').replaceWith('<img src="/images/loading.gif">' + '</img>');
} else {
$('.btn.ticket:eq(' + [index] + ')').removeClass('btn-ready-state');
$('.btn.ticket:eq(' + [index] + ')').removeClass('btn-working-state');
$('.btn.ticket:eq(' + [index] + ')').addClass('btn-completed-state');
$('.btn.ticket:eq(' + [index] + ')').find('.text').text('Added');
$('.btn.ticket:eq(' + [index] + ')').find('.state').addClass('done');
$('.btn.ticket:eq(' + [index] + ')').find('i').replaceWith('<i class="glyphicon glyphicon-ok state"></i>');
$('.btn.ticket:eq(' + [index] + ')').find('img').replaceWith('<i class="glyphicon glyphicon-ok state"></i>');
}
}).change(); //could be change() or trigger('change')
});
$(document).on("click", ".btn.ticket", function() {
var index = $(".btn.ticket").index(this);
$('#loading').val(index).change();
});
$(document).on("click", ".btn.next", function() {
$(this).removeClass('btn-ready-state');
$(this).addClass('btn-working-state');
$(this).find('.text').text('Working..');
$(this).find('.state').addClass('loading');
$(this).find('i').replaceWith('<img src="/images/loading.gif">' + '</img>');
});
</script>
This is a sample html of the button:
<button class="btn-ready-state"><span class="img"></span><span class="text"></span></button>
90% of the script changes the style. You said you like to indicate ajax? Look at this:
<script>
jQuery.ajaxSetup({
ajaxStart:function(){
jQuery('body').toggleClass('ajaxing', true);
},
ajaxStop:function(){
jQuery('body').toggleClass('ajaxing', false);
}
})
</script>
This is better because you dont need to repeat yourself (DRY-Principle).
So instead of doing this in javascript:
$(this).find('i').replaceWith('<img src="/images/loading.gif">' + '</img>');
You can now do all the graphical stuff you did in javascript in CSS:
.ajaxing i {
background-image: url(/images/loading.gif);
}
// for text you can use this:
.ajaxing .btn.ticket:active:before{
position:relative;
content:'Working...';
}
Or in anguarjs:
angular.module('app', []).value('loadManager', {
c: 0,
requested: function() { c++; document.body.class="ajaxing";},
responded: function() { c--; if(!c)document.body.class="";}
}).factory('loadingInterceptor', function(loadManager) {
return {
request: function(e) {
loadManager.requested();
return e;
},
response: function(e) {
loadManager.responded();
return e;
},
}
});
$httpProvider.interceptors.push('loadManager');
All of this is only an example. I do not know the complete HTML you are using.
Related
I have a custom button in summernote that has a dropdown of items "one", "two", "three" when I click on for example the text "one" the text is added at the start which is fine. But then when I click on "two" afterwards the text is also added at the start which produces this result.
twoone
I would like to have the following result
one
two
Update when I use this line
context.invoke("editor.pasteHTML", context.modules.editor.$editable[0].innerText ? "<br>" + $(this).html() : $(this).html() );
instead of
context.invoke('editor.insertText', $(this).html());
I get the following result wihch is better but the order is still incorrect
two
one
Here you can fiddle with my code
https://stackblitz.com/edit/angular-summernote-demo-n7xn2n?file=src%2Fapp%2Fapp.component.ts
Otherwise here is my code for the button that inserts the text
function customButtonGenerator(lstQuoteComments, title) {
return function (context) {
const ui = ($ as any).summernote.ui;
var i;
var listHtml = '';
for (i = 0; i < lstQuoteComments.length; i++) {
listHtml += '<li>' + lstQuoteComments[i] + '</li>';
}
const button = ui.buttonGroup([
ui.button({
className: 'dropdown-toggle',
contents:
'<i class="fa fa-comments text-primary"/><span id="summernot-caret" class="caret text-primary"></span>',
//tooltip: 'Comments', //Not working when howver over it top is not defined
data: {
toggle: 'dropdown',
},
}),
ui.dropdown({
className: 'drop-default summernote-list',
contents:
'<div id="container-comentario"><div id="dialog" title="' +
title +
'" ><h1 class="header-comentario">' +
title +
'</h1><ul id="summernote-list"><ul>' +
listHtml +
'</ul></div></div>',
callback: function ($dropdown) {
$dropdown.find('li').each(function () {
$(this).click(function () {
context.invoke('editor.insertText', $(this).html());
});
});
},
}),
]);
return button.render();
};
}
Thank you for your help.
As far as I can see, these answer don't quite get the question right.
You should append the button content to the existing content like this:
Example blitz - https://stackblitz.com/edit/angular-summernote-demo-ycvten?file=src%2Fapp%2Fapp.component.ts
Main code snippet:
...
callback: function ($dropdown) {
$dropdown.find('li').each(function () {
$(this).click(function () {
let newHtml = context.modules.editor.$editable[0].innerHTML
if (newHtml !== '') {
newHtml += '<br>'
}
newHtml += $(this).html()
context.invoke('code', newHtml)
})
})
}
...
I'll have a look if there is a way to keep track of the current cursor position, I think there must be. I'l update if that's possible, rather than just adding to the end.
You can try to replace this line in customButtonGenerator function:
context.invoke('editor.insertText', $(this).html());
With:
context.invoke('editor.pasteHTML', $(this).html());
OR
context.invoke('editor.pasteHTML', '<div>' + $(this).html() + '</div>');
Replace this line
context.invoke('editor.insertText', $(this).html());
with
context.invoke("code", context.modules.editor.$editable[0].innerHTML + '<br>' + $(this).html());
This will solve the issue.
How can I fix problem with jQuery function ".css" which works only when it is triggred by user (console, button, ...) ?
I'm using interval in .ready function for trigger it but it dosn't work. However .html function is changing the text properly.
$(document).ready(function()
{
setInterval(function()
{
$.get("./getData", function(data)
{
$(".text").html("" + data + " %");
$(".circle").css("border-width", "" + data + "px");
});
}, 1000);
});
Other border properties specified properly? Border color and weight? Its working fine when specified.
Your code looks fine, make sure data is numeric value and you have element with class name circle
jsFiddle
Try to call this function on window.onload.
<script>
function testFunction()
{
setInterval(function()
{
$.get("./getData", function(data)
{
$(".text").html("" + data + " %");
$(".circle").css("border-width", "" + data + "px");
});
}, 1000);
}
window.onload=testFunction;
</script>
Here's my code:
// Open modal window with links
$('.links').colorbox({speed:100, opacity:0.75, html:'<div id="links-colorbox"><h2>Download links</h2><textarea name="links"></textarea></div>'});
// Populate textarea with links
for(i in linkList) {
$('#links-colorbox textarea').append('http://site.com/' + linkList[i][0] + '/' + linkList[i][1] + '\n');
}
The problem is the textarea in the modal window doesn't get populated, probably because it's inserted into the DOM on the fly with the modal window plugin I'm using.
Is there a way I can make this work? Thanks.
Use oncomplete callback:
$('.links').colorbox({
speed:100,
opacity:0.75,
html:'<div id="links-colorbox"><h2>Download links</h2><textarea name="links"></textarea></div>',
onComplete: function() {
for(i in linkList) {
$('#links-colorbox textarea').append('http://site.com/' + linkList[i][0] + '/' + linkList[i][1] + '\n');
}
}
});
Below you can see that I store the results of the jquery selector in an array. I then use this array to perform other functions. This example here doesn't seem to work, it's behaving as if the var/array is a live selector, not the results when they were instantiated.
function flipIt(elementId){
if (window.jQuery){
var thisVisibleArray = $('#' + elementId + ' div:visible');
var thisInvisibleArray = $('#' + elementId + ' > div:visible');
$(thisInvisibleArray).slideDown("fast");
$(thisVisibleArray).slideUp("fast");
/*
if ($('#flip1').is(":visible")){
$('#flip1').slideUp("fast", function(){
$('#flip2').slideDown();
});
} else {
$('#flip2').slideUp("fast", function(){
$('#flip1').slideDown();
});
}*/
}
}
In order to select the invisible div elements you have to use not and not ">". And also the 2 variables you defined are already jquery element array so you dont have to use $(). Try this
function flipIt(elementId){
if (window.jQuery){
var thisVisibleArray = $('#' + elementId + ' div:visible');
var thisInvisibleArray = $('#' + elementId + ' div:not(:visible)');
thisInvisibleArray.slideDown("fast");
thisVisibleArray.slideUp("fast");
/*if ($('#flip1').is(":visible")){
$('#flip1').slideUp("fast", function(){
$('#flip2').slideDown();
});
} else {
$('#flip2').slideUp("fast", function(){
$('#flip1').slideDown();
});
}*/
}
}
You are storing the selected elements in a variable, and then you are trying to get a jQuery object out of another jQuery object. Just do:
thisInvisibleArray.slideDown("fast");
thisVisibleArray.slideUp("fast");
Also, they are not arrays, but jQuery objects.
I'm trying to use AJAX to dynamically generate a JquerUI Accordion based on what is selected in a box. Currently I have
<div style="display:none" id="testselect">
</div>
With JS
$("#courseselect").change(function () {
$("#testselect").html(""); // Empty any previous data
$("#testselect").css("display", "block"); // Display it if it was hidden
$.getJSON('json.php?show=tests&courseid=' + $(this).val(), function(data) {
for(x in data)
{
$("#testselect").append("<h3 value=\"" + data[x].uno + "\">" + data[x].name + "</h3>");
$("#testselect").append("<div>Foo</div>");
}
$("#testselect").accordion({ change:function(event, ui) { courseid = ui.newHeader.attr("value");
} });
});
});
Now this works the first time I change my selection, but after that it reverts to plain old unformatted HTML. As if the call to .accordion() was never done. I'm guessing this has something to do with JQuery not wanting me to format something twice, but I really have no idea.
Try to destroy the accordion before you empty the div and start again:
$("#courseselect").change(function () {
$("#testselect")
.accordion("destroy")
.empty() // equivalent to .html("");
$.getJSON(...
More info here.
Good luck!