I'm using Quill as an editor. One of the functions I made adds timestamps to the text. The blot works fine and timestamps are added as expected. When the data is loaded back into the Quill editor from the database, though, instead of the timestamp value, Quill marks it as 'True' instead. The timestamp data is saved in the database properly. I'm having an issue figuring out how to make Quill load that data properly.
This is what the timestamp looks like in the editor:
enter image description here
This is what it looks like when inspected:
enter image description here
Here's what it looks like after loading (editor view and code in inspector):
enter image description here
enter image description here
Here's the code I have for my blot currently:
var Embed = Quill.import('blots/embed');
class QuillHashtag extends Embed {
static create(value) {
let node = super.create(value);
node.innerHTML = `${value}`;
node.setAttribute("data", value);
return node;
}
static formats(node) {
// We will only be called with a node already
// determined to be a Link blot, so we do
// not need to check ourselves
return node.getAttribute('data');
}
}
QuillHashtag.blotName = 'timeStamp';
QuillHashtag.className = 'quill-hashtag';
QuillHashtag.tagName = 'timeStamp';
Quill.register({
'formats/timeStamp': QuillHashtag
});
Here's my code for saving the editor:
function saveTrascription() {
var file_data = document.getElementById("transcriptEditorBox").innerHTML;
var jobID = document.getElementById("jobSelect").value;
var set = "set";
$.ajax({
type: "POST",
url: "/transcribe/worker.php",
data: {
transcriptionText: file_data,
saveTranscription: set,
jobID: jobID
},
success: function (response) {
toastr.success(response);
}
});
}
Here's my code for loading the data:
function getTranscriptionJob() {
var jobID = document.getElementById("jobSelect").value;
var audioPlayer = document.getElementById("audioPlayerDiv");
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function () {
if (this.readyState == 4 && this.status == 200) {
var returnedData = JSON.parse(this.responseText);
if (
returnedData.transcriptionText ==
"Transcription job not finshed. Try again shortly."
) {
toastr.warning("Transcription job not finshed. Try again shortly.");
return true;
} else {
document.getElementById("jobSelectRow").style.display = "none";
document.getElementById("editorRow").style.display = "block";
var delta = quill.clipboard.convert(returnedData.transcriptionText);
quill.setContents(delta, 'silent');
//quill.clipboard.dangerouslyPasteHTML(0, returnedData.transcriptionText);
audioPlayer.innerHTML =
'<audio onloadeddata="initProgressBar()" onplay="showPauseButton()" onpause="showPlayButton()" ontimeupdate="updateProgressBar()" controls id="audioPlayer" ><source src="' +
returnedData.audioFile +
'" type="audio/mpeg" >Your browser does not support the audio element.</audio>';
toastr.info("Press Alt+P to play/pause the audio file.");
return true;
}
}
};
var url = "/transcribe/worker.php?getTranscriptionJob=set&jobID=" + jobID;
xhttp.open("GET", url, true);
xhttp.send();
}
Any help with this is really appreciated! I'm very lost on what is going wrong. I think it has something to do with that formats snippet in the blot code, but not entirely sure.
I have this ajax call here in a script tag at the bottom of my page. Everything works fine! I can set a breakpoint inside the 'updatestatus' action method in my controller. My server gets posted too and the method gets called great! But when I put the javascript inside a js file the ajax call doesn't hit my server. All other code inside runs though, just not the ajax post call to the studentcontroller updatestatus method.
<script>
$(document).ready(function () {
console.log("ready!");
alert("entered student profile page");
});
var statusdropdown = document.getElementById("enumstatus");
statusdropdown.addEventListener("change", function (event) {
var id = "#Model.StudentId";
var url = '#Url.Action("UpdateStatus", "Student")';
var status = $(this).val();
$.post(url, { ID: id, Status: status }, function (data) {
// do something with the returned value e.g. display a message?
// for example - if(data) { // OK } else { // Oops }
});
var e = document.getElementById("enumstatus");
if (e.selectedIndex == 0) {
document.getElementById("statusbubble").style.backgroundColor = "#3fb34f";
} else {
document.getElementById("statusbubble").style.backgroundColor = "#b23f42";
}
}, false);
</script>
Now I put this at the bottom of my page now.
#section Scripts {
#Scripts.Render("~/bundles/studentprofile")
}
and inside my bundle.config file it looks like this
bundles.Add(new ScriptBundle("~/bundles/studentprofile").Include(
"~/Scripts/submitstatus.js"));
and submitstatus.js looks like this. I know it enters and runs this code because it I see the alert message and the background color changes. So the code is running. Its just not posting back to my server.
$(document).ready(function () {
console.log("ready!");
alert("submit status entered");
var statusdropdown = document.getElementById('enumstatus');
statusdropdown.addEventListener("change", function (event) {
var id = "#Model.StudentId";
var url = '#Url.Action("UpdateStatus", "Student")';
var status = $(this).val();
$.post(url, { ID: id, Status: status }, function (data) {
// do something with the returned value e.g. display a message?
// for example - if(data) { // OK } else { // Oops }
});
var e = document.getElementById('enumstatus');
if (e.selectedIndex == 0) {
document.getElementById("statusbubble").style.backgroundColor = "#3fb34f";
} else {
document.getElementById("statusbubble").style.backgroundColor = "#b23f42";
}
}, false);
});
In the console window I'm getting this error message.
POST https://localhost:44301/Student/#Url.Action(%22UpdateStatus%22,%20%22Student%22) 404 (Not Found)
Razor code is not parsed in external files so using var id = "#Model.StudentId"; in the main view will result in (say) var id = 236;, in the external script file it will result in var id = '#Model.StudentId'; (the value is not parsed)
You can either declare the variables in the main view
var id = "#Model.StudentId";
var url = '#Url.Action("UpdateStatus", "Student")';
and the external file will be able to access the values (remove the above 2 lines fro the external script file), or add them as data- attributes of the element, for example (I'm assuming enumstatus is a dropdownlist?)
#Html.DropDownListFor(m => m.enumStatus, yourSelectList, "Please select", new { data_id = Model.StudentId, data_url = Url.Action("UpdateStatus", "Student") })
which will render something like
<select id="enumStatus" name="enumStatus" data-id="236" data-url="/Student/UpdateStatus">
Then in the external file script you can access the values
var statusbubble = $('#statusbubble'); // cache this element
$('#enumStatus').change(function() {
var id = $(this).data('id');
var url = $(this).data('url');
var status = $(this).val();
$.post(url, { ID: id, Status: status }, function (data) {
....
});
// suggest you add/remove class names instead, but if you want inline styles then
if (status == someValue) { // the value of the first option?
statusbubble.css('backgroundColor', '#3fb34f');
} else {
statusbubble.css('backgroundColor', '#b23f42');
};
});
I'm trying to get the transposh plugin to translate everytime the cart is updated dynamically. Currently, the plugin will translate and then woocommerce would update the cart thus the translations disappear.
I found the following code in WooCommerce's checkout.js:
// Event for updating the checkout
$('body').bind('update_checkout', function() {
clearTimeout(updateTimer);
update_checkout();
});
I believe this is the code (I can only find the minified version of it) for how transposh gets the translations going in transposh.js:
(function(c){function D(b,a){if(0!==c.trim(a).length){var d=function(){var b=c(this).attr("id").substr(c(this).attr("id").lastIndexOf("_")+1),a=c("#"+e+"img_"+b);c("#"+e+b).attr("data-source",1);a.removeClass("tr-icon-yellow").removeClass("tr-icon-green").addClass("tr-icon-yellow")};c("*[data-token='"+b+"'][data-hidden!='y']").html(a).each(d);c("*[data-token='"+b+"'][data-hidden='y']").attr("data-trans",a).each(d)}}function E(b,a){clearTimeout(v);h.push(b);r.push(a);D(b,a);v=setTimeout(function(){var b=
{ln0:t_jp.lang,sr0:s,action:"tp_translation",items:h.length},a;for(a=0;a<h.length;a+=1)b["tk"+a]=h[a],b["tr"+a]=r[a],t+=c("*[data-token='"+h[a]+"']").size();c.ajax({type:"POST",url:t_jp.ajaxurl,data:b,success:function(){var b=t/k*100;t_jp.progress&&c("#"+m).progressbar("value",b)}});r=[];h=[]},200)}function l(b,a){E(b,c("<div>"+c.trim(a)+"</div>").text());var d=(k-c("."+e+'[data-source=""]').size())/k*100;t_jp.progress&&c("#"+n).progressbar("value",d)}function w(b,a,d){c.ajax({url:t_jp.ajaxurl,dataType:"json",
type:"GET",data:{action:"tp_gp",tl:d,q:b},success:a})}function x(b,a){w(a,function(a){c(a.results).each(function(a){l(b[a],this)})},t_jp.lang)}function y(b,a,d){c.ajax({url:"https://www.googleapis.com/language/translate/v2",dataType:"jsonp",data:{key:t_jp.google_key,q:b,target:d,source:t_jp.olang},traditional:!0,success:a})}function F(b,a){y(a,function(d){"undefined"!==typeof d.error?x(b,a):c(d.data.translations).each(function(a){l(b[a],this.translatedText)})},t_jp.lang)}function p(b,a,d){if(t_jp.msn_key){var f=
"[";c(b).each(function(a){f+='"'+encodeURIComponent(b[a].replace(/[\\"]/g,"\\$&").replace(/(\r\n|\n|\r)/gm," "))+'",'});f=f.slice(0,-1)+"]";c.ajax({url:"//api.microsofttranslator.com/V2/Ajax.svc/TranslateArray?appId="+t_jp.msn_key+"&to="+d+"&texts="+f,dataType:"jsonp",jsonp:"oncomplete",success:a})}else 1===z?setTimeout(function(){p(b,a,d)},500):(z=1,c.getScript("//www.microsofttranslator.com/ajax/v2/toolkit.ashx?loc=en&toolbar=none",function(){t_jp.msn_key=_mstConfig.appId;p(b,a,d)}))}function G(b,
a){s=2;p(a,function(a){c(a).each(function(a){l(b[a],this.TranslatedText)})},t_jp.binglang)}function A(b,a,d){c.ajax({url:"http://api.apertium.org/json/translate",data:{q:b,langpair:t_jp.olang+"|"+d,markUnknown:"no"},dataType:"jsonp",traditional:!0,success:a})}function H(b,a){s=3;A(a,function(a){200<=a.responseStatus&&300>a.responseStatus&&(void 0!==a.responseData.translatedText?l(b[0],a.responseData.translatedText):c(a.responseData).each(function(a){200===this.responseStatus&&l(b[a],this.responseData.translatedText)}))},
t_jp.lang)}function B(b,a){!t_jp.msn||"2"!==t_jp.preferred&&void 0!==t_jp.google?!t_jp.apertium||"en"!==t_jp.olang&&"es"!==t_jp.olang?t_jp.google_key?F(b,a):x(b,a):H(b,a):G(b,a)}function u(){var b=[],a=0,d=[],f=[];c("."+e+'[data-source=""]').each(function(){var e=c(this).attr("data-token"),g=c(this).attr("data-orig");void 0===g&&(g=c(this).html());1!==b[g]&&(b[g]=1,a+encodeURIComponent(g).length>I&&(B(f,d),a=0,d=[],f=[]),a+=encodeURIComponent(g).length,f.push(e),d.push(g))});B(f,d)}function C(b){"function"===
typeof c.xLazyLoader?b():(t_jp.$=c,c.getScript(t_jp.plugin_url+"/js/lazy.js",b))}function q(b){q.hit?b():(q.hit=!0,C(function(){c.fn.propAttr=c.fn.prop||c.fn.attr;c.xLazyLoader({js:t_jp.jQueryUI+"jquery-ui.min.js",css:t_jp.jQueryUI+"themes/"+t_jp.theme+"/jquery-ui.css",success:b})}))}var I=1024,k,e=t_jp.prefix,n=e+"pbar",m=n+"_s",s=1,t=0,v,h=[],r=[],z=0;t_jp.dgpt=w;t_jp.dgt=y;t_jp.dmt=p;t_jp.dat=A;t_jp.tfl=C;t_jp.tfju=q;t_jp.at=u;c(function(){t_jp.msn&&(t_jp.binglang=t_jp.lang,"zh"===t_jp.binglang?
t_jp.binglang="zh-chs":"zh-tw"===t_jp.binglang?t_jp.binglang="zh-cht":"mw"===t_jp.binglang&&(t_jp.binglang="mww"));c("."+e+"setdeflang").click(function(){c.ajax({url:t_jp.ajaxurl,data:{action:"tp_cookie"},cache:!1});c("."+e+"setdeflang").hide("slow");return!1});k=c("."+e+'[data-source=""]').size();c.ajaxSetup({cache:!0});k&&!t_jp.noauto&&(t_jp.google||t_jp.msn||t_jp.apertium)&&(t_jp.progress?q(function(){c("#"+e+"credit").css({overflow:"auto"}).append('<div style="float: left;width: 90%;height: 10px" id="'+
n+'"/><div style="margin-bottom:10px;float:left;width: 90%;height: 10px" id="'+m+'"/>');c("#"+n).progressbar({value:0});c("#"+m).progressbar({value:0});c("#"+m+" > div").css({background:"#28F828",border:"#08A908 1px solid"});u()}):u());t_jp.edit&&c.getScript(t_jp.plugin_url+"/js/transposhedit.js")})})(jQuery);
What should I add in the checkout.js to fire the translations everytime the cart is updated?
Let me know what other details I should provide.
EDIT: I should note that I was told that the cart is being updated via AJAX. Upon research, the plugin creator of transposh had suggested users to look at the on_init function in transposh.php
This is the on_init function:
/**
* Setup a buffer that will contain the contents of the html page.
* Once processing is completed the buffer will go into the translation process.
*/
function on_init() {
tp_logger('init ' . $_SERVER['REQUEST_URI'], 4);
// the wp_rewrite is not available earlier so we can only set the enable_permalinks here
if (is_object($GLOBALS['wp_rewrite'])) {
if ($GLOBALS['wp_rewrite']->using_permalinks() && $this->options->enable_permalinks) {
tp_logger("enabling permalinks");
$this->enable_permalinks_rewrite = TRUE;
}
}
// this is an ajax special case, currently crafted and tested on buddy press, lets hope this won't make hell break loose.
// it basically sets language based on referred when accessing wp-load.php (which is the way bp does ajax)
tp_logger(substr($_SERVER['SCRIPT_FILENAME'], -11), 5);
if (substr($_SERVER['SCRIPT_FILENAME'], -11) == 'wp-load.php') {
$this->target_language = transposh_utils::get_language_from_url($_SERVER['HTTP_REFERER'], $this->home_url);
$this->attempt_json = true;
}
//buddypress old activity
if (#$_POST['action'] == 'activity_get_older_updates') {
$this->target_language = transposh_utils::get_language_from_url($_SERVER['HTTP_REFERER'], $this->home_url);
$this->attempt_json = true;
}
tp_logger($_SERVER['REQUEST_URI'], 5);
if (strpos($_SERVER['REQUEST_URI'], '/wpv-ajax-pagination/') === true) {
tp_logger('wpv pagination', 5);
$this->target_language = transposh_utils::get_language_from_url($_SERVER['HTTP_REFERER'], $this->home_url);
}
// load translation files for transposh
load_plugin_textdomain(TRANSPOSH_TEXT_DOMAIN, false, dirname(plugin_basename(__FILE__)) . '/langs');
//set the callback for translating the page when it's done
ob_start(array(&$this, "process_page"));
}
Here is the function for update_checkout()
function update_checkout() {
if (xhr) xhr.abort();
if ( $('select#shipping_method').size() > 0 || $('input#shipping_method').size() > 0 )
var method = $('#shipping_method').val();
else
var method = $('input[name=shipping_method]:checked').val();
var payment_method = $('#order_review input[name=payment_method]:checked').val();
var country = $('#billing_country').val();
var state = $('#billing_state').val();
var postcode = $('input#billing_postcode').val();
var city = $('input#billing_city').val();
var address = $('input#billing_address_1').val();
var address_2 = $('input#billing_address_2').val();
if ( $('#shiptobilling input').is(':checked') || $('#shiptobilling input').size() == 0 ) {
var s_country = country;
var s_state = state;
var s_postcode = postcode;
var s_city = city;
var s_address = address;
var s_address_2 = address_2;
} else {
var s_country = $('#shipping_country').val();
var s_state = $('#shipping_state').val();
var s_postcode = $('input#shipping_postcode').val();
var s_city = $('input#shipping_city').val();
var s_address = $('input#shipping_address_1').val();
var s_address_2 = $('input#shipping_address_2').val();
}
$('#order_methods, #order_review').block({message: null, overlayCSS: {background: '#fff url(' + woocommerce_params.ajax_loader_url + ') no-repeat center', backgroundSize: '16px 16px', opacity: 0.6}});
var data = {
action: 'woocommerce_update_order_review',
security: woocommerce_params.update_order_review_nonce,
shipping_method: method,
payment_method: payment_method,
country: country,
state: state,
postcode: postcode,
city: city,
address: address,
address_2: address_2,
s_country: s_country,
s_state: s_state,
s_postcode: s_postcode,
s_city: s_city,
s_address: s_address,
s_address_2: s_address_2,
post_data: $('form.checkout').serialize()
};
xhr = $.ajax({
type: 'POST',
url: woocommerce_params.ajax_url,
data: data,
success: function( response ) {
if ( response ) {
var order_output = $(response);
$('#order_review').html(order_output.html());
$('body').trigger('updated_checkout');
}
}
});
}
After a bit of digging , and because im not php expert neither wp expert , but i can tell where the issue is.
First of all you should understand what add_action is , it is well explained here
If you needed to create an AJAX handler for an "add_foobar" request, you would create a hook like this:
add_action( 'wp_ajax_add_foobar', 'prefix_ajax_add_foobar' );
add_action( 'wp_ajax_nopriv_add_foobar', 'prefix_ajax_add_foobar' );
function prefix_ajax_add_foobar() {
// Handle request then generate response using WP_Ajax_Response
}
Using the above example, any time an AJAX request is sent to WordPress, and the request's 'action' property is set to 'add_foobar', this hook will be automatically executed. For example, the following code would execute the above hook.
jQuery.post(
ajaxurl,
{
'action': 'add_foobar',
'data': 'foobarid'
},
function(response){
alert('The server responded: ' + response);
}
);
so now you got how actions works , then you have to get how the transposh.php ajax part works , from the transposh.php file ( i recommend you open the file in a good text editor like sublime text ) , in line 437 :
//buddypress old activity
if (#$_POST['action'] == 'activity_get_older_updates') {
$this->target_language = transposh_utils::get_language_from_url($_SERVER['HTTP_REFERER'], $this->home_url);
$this->attempt_json = true;
}
this simply tells our script to fire translation when this action is called, what you have to do is customizing this line a bit so it fires upon you ajax request (update_checkout()).
if you check update_checkout() function you will find the corresponding action : 'woocommerce_update_order_review'
Solution:
1. Add you wp actions
add_action( 'wp_woocommerce_update_order_review', 'woocommerce_update_order_review' );
//preferably add this to line 207 in transposh.php with other add actions.
2. Instead of adding your own function , just modify the current buddypress example.
if (#$_POST['action'] == 'activity_get_older_updates')
to be
if (#$_POST['action'] == 'activity_get_older_updates' || #$_POST['action'] == 'woocommerce_update_order_review' )
//fire translation if action is equal to buddypress activity get older updates or action is equal to woocommerce update checkout.
3. this guy recommends adding following condition to line 352 in transposh.php
if ($this->is_special_page($_SERVER['REQUEST_URI']))
to be
if ($this->is_special_page($_SERVER['REQUEST_URI'])&& !$this->attempt_json)
found here : http://cl.ly/Shdn/o
I hope i had a link to your page where you are using this , but you could not provide an example , so i hope this solution will work as it was meant to be.
In stages, I setup my .Net MVC solution and ensured both Angular JS and KendoUI are working independently.
app.js:
var app = angular.module("app", ['kendo.directives']);
and in my controller, I have the following defined:
app.controller('contentTypesController', ['$scope', '$log', 'contentTypesRepository',
function ($scope, $log, contentTypesRepository) {
var a = {};
$scope.status;
$scope.contentTypes;
$scope.contentTypeOptions;
// for testing purposes, but not used - used for navigation properties
$scope.users;
getContentTypes();
function getContentTypes() {
// call the data repository
contentTypesRepository.getList()
.success(function (contentTypes) {
//console.log(contentTypes.value[0].Description);
//$log.log(contentTypes.value[0].Description)
$scope.contentTypes = contentTypes;
$scope.contentTypeOptions = {
dataSource: {
data: contentTypes
},
dataTextField: "Description",
dataValueField: "ContentTypeId",
optionLabel: "Select a Content Type"
};
})
.error(function (error) {
$scope.status = 'Unable to load data: ' + error.message;
});
}
$scope.updateContentTypes = function (id) {
var contentType;
for (var i = 0; i < $scope.contentTypes.length; i++) {
var currentType = $scope.contentTypes[i];
if (currentType.ID === id) {
contentType = currentType;
break;
}
}
};
$scope.insertContentType = function () {
// get contentType description from the client
var contentType = { 'Description': $scope.newContentType };
contentTypesRepository.insert(contentType)
.success(function () {
$scope.status = 'Added new content type. Refreshing list.';
// add the new content type to the client-side collection
$scope.contentTypes.value.push(
{ 'Description': $scope.newContentType }
);
$scope.newContentType = "";
})
.error(function (error) {
$scope.status = 'Unable to insert new content type: ' + error.message;
});
};
$scope.deleteContentType = function(id) {
contentTypesRepository.remove(id)
.success(function () {
$scope.status = 'Deleted content type. Refreshing list.';
for (var i = 0; i < $scope.contentTypes.length; i++) {
var contentType = $scope.contentTypes[i];
if (contentType.ID === id) {
// remove the content type from the client-side collection
$scope.contentTypes.splice(i, 1);
break;
}
}
// navigation properties = null
// $scope.xxxx = null;
})
.error(function (error) {
$scope.status = 'Unable to delete content type: ' + error.message;
});
};
// get some navigation property
//$scope.getCustomerOrders = function (id) {
// dataFactory.getOrders(id)
// .success(function (orders) {
// $scope.status = 'Retrieved orders!';
// $scope.orders = orders;
// })
// .error(function (error) {
// $scope.status = 'Error retrieving customers! ' + error.message;
// });
//};
$scope.addContentType = function () {
//return $scope.newContentType.$save();
$scope.contentTypes.value.push(
{ 'Description': $scope.newContentType }
);
$scope.newContentType = "";
}
In following the Angluar/Kendo examples here, I added code related to $scope.contentTypeOptions.
In my view:
<select kendo-drop-down-list k-options="contentTypeOptions"></select>
Which displays a dropdown, but no data.
I am able to view the data in a ng-repeater:
<ul>
<li ng-repeat="contentType in contentTypes.value">
{{ contentType.Description }}
</li>
</ul>
And the raw data by {{ contentTypeOptions }}.
Since the repeater uses contentTypes.value, I tried this as well in
$scope.contentTypeOptions = {
dataSource: {
data: contentTypes.value // tried both contentTypes and contentTypes.value
},
dataTextField: "Description",
dataValueField: "ContentTypeId",
optionLabel: "Select a Content Type"
};
... which is based on the JSON data:
Ultimately, I would like to get all the CRUD hooked up for a grid (which I have done in the past with OData, but now adding AngularJS to the mix) and thought simply displaying the data in an Angular/Kendo mix would be a good start. I'm hoping that after getting this pinned down the rest will be simple, and appreciate any suggestions.
Your code is a bit confusing since methods like $scope.updateContentTypes treat $scope.contentTypes as an array, but at the same time contentTypes appears to be an object with a property value which is an array.
One thing to be aware of is that Kendo UI widgets will convert your array to a Kendo DataSource internally. This means that changes you make to $scope.contentTypes won't affect the items in your data source in $scope.contentTypeOptions.
Another issue is that there is no full two-way binding between widgets and the data source in angular-kendo, and until recently, the data source wouldn't update at all unless you specifically declared it as a DataSource. There have been some improvements lately, although it's still not fully integrated, as far as I can see.
(you can try creating a deep watch on the data yourself, but that may create performance problems; see related post here).
Your dropdown doesn't show the data because you replace $scope.contentTypeOptions after creating the widget, and there is no $watch on that property that would update the widget with these options.
You can either create a DataSource explicitly and update that with:
$scope.contentTypeOptions.dataSource.data(contentType.value);
or you can use the attribute:
k-data-source="contentTypes"
which will create a $watch on $scope.contentTypes, so when you replace it, the widget will update as well.
Maybe this basic (although admittedly a bit messy) example will help you somewhat (I set up the 2nd dropdown in the same way you did; the "change" button updates the data source).
You will need to use the Angular Kendo bindings from Kendo labs.
Here is a an article with live demo and full source code:
http://blog.longle.io/2014/05/01/angularjs-kendo-ui-using-angular-kendo-with-asp-net-mvc-5-web-api-odata
I have a YUI dialog that submits a form to a Java servlet. The servlet returns html and javascript. I take the response and put it into a div on the page and then eval the javascript that is within the div.
My problem is that I get an error in the firebug console saying "YAHOO is not defined" as soon as the servlet returns.
I do not include the YUI js files in the servlet as I didn't think I would need them, I would expect the files included in the head of the main page would be sufficient.
If I remove all references to YUI from the javascript returned by my servlet then everything works well.
What should I do to stop getting this error as soon as my servlet returns?
My Servlet returns something along the lines of:
<div id="features">some html to display</div>
<script id="ipadJS" type='text/javascript'>
var editButton1 = new YAHOO.widget.Button('editButton1', { onclick: { fn: editButtonClick, obj: {id: '469155', name : 'name 1'} } });
var editButton2 = new YAHOO.widget.Button('editButton2', { onclick: { fn: editButtonClick, obj: {id: '84889', name : 'name 2'} } });
</script>
Here is the code that I used to create the dialog, i use the handleSuccess function to put my response from my servlet into the page (note that even though im not actively putting the javascript into the page it still throws the 'YAHOO not defined' error.):
YAHOO.namespace("ipad");
YAHOO.util.Event.onDOMReady(function () {
// Remove progressively enhanced content class, just before creating the module
YAHOO.util.Dom.removeClass("createNewFeature", "yui-pe-content");
// Define various event handlers for Dialog
var handleSubmit = function() {
this.submit();
};
var handleCancel = function() {
this.cancel();
};
var handleSuccess = function(o) {
var response = o.responseText;
var div = YAHOO.util.Dom.get('features');
div.innerHTML = response;
};
var handleFailure = function(o) {
alert("Submission failed: " + o.status);
};
// Instantiate the Dialog
YAHOO.ipad.createNewFeature = new YAHOO.widget.Dialog("createNewFeature",
{ width : "450px",
fixedcenter : true,
visible : false,
constraintoviewport : true,
buttons : [ { text:"Submit", handler:handleSubmit, isDefault:true },
{ text:"Cancel", handler:handleCancel } ]
});
// Validate the entries in the form to require that both first and last name are entered
YAHOO.ipad.createNewFeature.validate = function() {
var data = this.getData();
return true;
};
YAHOO.ipad.createNewFeature.callback = { success: handleSuccess,
failure: handleFailure,
upload: handleSuccess };
// Render the Dialog
YAHOO.ipad.createNewFeature.render();
var createNewFeatureShowButton = new YAHOO.widget.Button('createNewFeatureShow');
YAHOO.util.Event.addListener("createNewFeatureShow", "click", YAHOO.ipad.clearFeatureValues, YAHOO.ipad.clearFeatureValues, true);
var manager = new YAHOO.widget.OverlayManager();
manager.register(YAHOO.ipad.createNewFeature);
});
I don't know your use case exactly, but if you just need to create some buttons on the fly based on server response, than it would IMO be better to return JSON or XML data with the variable data and then create the buttons. Something like
var reply = eval('(' + o.responseText + ')');
var editButton1 = new YAHOO.widget.Button('editButton1',
{ onclick: { fn: editButtonClick,
obj: {id: reply[id], name : reply[name]}
} })
And if you really want to append a script node, then the following approach should work:
var response = o.responseText;
var snode = document.createElement("script");
snode.innerHTML = response;
document.body.appendChild(snode);