I have a problem where I want to pass the value of a CK editor on to a Monaco editor. I can get the value from Monaco to CK but not the other way around. I can also see the value update while debugging but it does not seem to work somehow.
So what i want is when I type something in the CK editor and I press the button to switch to Monaco to have the value of the CK editor in the Monaco editor
This is the javasciprt :
function CkEditor(id, readonly, dotNetReference) {
CKEDITOR.replace(id, {
customConfig: '../ckeditor/config.js'
});
var editor = CKEDITOR.instances[id];
var editorId = editor.id;
var monacoEditor = document.getElementById("monaco_" + editor.name);
// Hide toolbar while loading
editor.on('loaded', () => {
document.getElementById(editorId + '_top').style.display = 'none';
});
editor.on('instanceReady', () => {
EnableCkEditor(id, readonly);
});
editor.on('change', () => {
var data = editor.getData();
if (data === '') {
data = null;
}
dotNetReference.invokeMethodAsync('EditorHasChanged', data);
});
editor.on('focus', (id) => {
editor.focusManager.focus();
document.getElementById(editorId + '_top').style.display = 'block';
editor.on('afterCommandExec', (event) => {
var commandName = event.data.name;
if (commandName === 'enableMonaco') {
if (monacoIsEnabled === false) {
document.getElementById(editorId + '_contents').style.display = 'none';
monacoEditor.classList.remove('monaco-wrapper');
monacoIsEnabled = true;
}
else {
editor.setData(monacoEditorData.value);
document.getElementById(editorId + '_contents').style.display = 'block';
monacoEditor.classList.add('monaco-wrapper');
monacoIsEnabled = false;
}
}
});
});
editor.on('blur', () => {
if (!monacoIsEnabled) {
document.getElementById(editorId + '_top').style.display = 'none';
}
});
}
function setCkEditorValue(value) {
monacoEditorData.value = value;
}
function CkEditorDestroy(id) {
var editor = CKEDITOR.instances[id];
editor.destroy();
delete editor;
}
function EnableCkEditor(id, readonly) {
var editor = CKEDITOR.instances[id];
if (editor) {
var editId = editor.id;
var editorBody = document.getElementById(editId + '_contents');
if (readonly === true) {
editorBody.classList.add('disabled_class');
}
else {
editorBody.classList.remove('disabled_class');
}
}
}
This is the component where it switches between Monaco and CK :
#inherits MarkupEditorComponent
#Value
<div id="wrapper">
<div class="ck-editor-wrapper">
<CkEditor Value="#Value" ValueChanged="#ValueChanged" Readonly="#Readonly" id="#Id"/>
</div>
<div class="monaco-wrapper" id="monaco_#Id">
<CodeEditor Value="#Value" ValueChanged="#ValueChanged" Readonly="#Readonly"/>
</div>
</div>
This is the CKEditor.razor
#inherits CkEditorComponent
<div id="wrapper">
<div class="ck-editor-wrapper">
<textarea #attributes="AdditionalAttributes"
id="#Id"
class="CssClass"
value="#Value"></textarea>
</div>
</div>
And as last the CKEditor.razor.cs
public class CkEditorComponent : BaseComponent
{
string _id = $"CKEditor{Guid.NewGuid().ToString().ToLower().Replace("-", string.Empty)}";
[Parameter]
public string Value { get; set; }
[Parameter]
public EventCallback<string> ValueChanged { get; set; }
[Parameter]
public bool Readonly { get; set; }
[Parameter]
public IReadOnlyDictionary<string, object> AdditionalAttributes { get; set; }
[Parameter]
public string Id
{
get => _id;
set => _id = value;
}
protected override async Task OnInitializedAsync()
{
await EditorHasChanged(Value);
}
protected override async Task OnParametersSetAsync()
{
await EnableEditor(Readonly);
await base.OnParametersSetAsync();
}
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
await JsRuntime.InvokeVoidAsync("CkEditor", Id, Readonly, DotNetObjectReference.Create(this));
}
}
[JSInvokable(nameof(EditorHasChanged))]
public Task EditorHasChanged(string data)
{
Value = data;
ValueChanged.InvokeAsync(data);
return Task.CompletedTask;
}
protected override void Dispose(bool disposing)
{
JsRuntime.InvokeVoidAsync("CkEditorDestroy", Id);
base.Dispose(disposing);
}
private async Task EnableEditor(bool enabled)
{
await JsRuntime.InvokeVoidAsync("EnableCkEditor", Id, enabled);
}
}
You might need to invoke StateHasChanged() inside EditorHasChanged(string data). A similar issue here.
Related
I have 4 Views(index view, navigation bar view, Partial view1, partialview2) in One controller
I'd like to switch The Partial View in index view when click navbaritem.
I set LeftPanelPartial in #section.
If I click navbar item, switch ProdFViewPartial() to ProdJViewPartial()
How Can I Get This.
check my code
Controller
namespace DXWMes.Controllers
{
public class ProdController : Controller
{
// GET: Prod
public ActionResult Index()
{
ProdRepository ProdRepo = new ProdRepository();
return View(ProdRepo.GetProdFData("1", "F11", "20220901"));
}
public ActionResult ProdFViewPartial()
{
ProdRepository ProdRepo = new ProdRepository();
return PartialView("ProdFViewPartial",ProdRepo.GetProdFData("1", "F11", "20220901"));
}
public ActionResult ProdJViewPartial()
{
ProdRepository ProdRepo = new ProdRepository();
return View("ProdJViewPartial", ProdRepo.GetProdJData("1", "20220901"));
}
VIEW - Index
#model List<DXWMes.Model.ProdFModel>
#{
ViewBag.Title = "Prod";
Layout = "~/Views/Shared/_Layout.cshtml";
}
#section Head {
<link rel="stylesheet" type="text/css" href="#Url.Content("~/Content/ProdView.css")" />
<script type="text/javascript" src="#Url.Content("~/Content/ProdView.js")"></script>
}
#section LeftPanelContent {
#Html.Partial("LeftPanelPartial")
}
#section RightPanelContent {
<div class="settings-content">
<h2>Settings</h2>
<p>Place your content here</p>
</div>
}
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
#Html.Partial("ProdFViewPartial")
}
<div id="detailView"> </div>
View - LeftPanelPartial
<h3 class="leftpanel-section section-caption">Production</h3>
#Html.DevExpress().NavBar(navBarSettings =>
{
navBarSettings.Name = "NavBar";
navBarSettings.AllowSelectItem = true;
navBarSettings.ShowGroupHeaders = false;
navBarSettings.Width = Unit.Percentage(100);
navBarSettings.ControlStyle.CssClass = "ProdNavbar";
navBarSettings.Styles.Item.CssClass = "item";
navBarSettings.Groups.Add(group =>
{
group.Items.Add(item =>
{
item.Name = "ProdE1";
item.Selected = true;
});
group.Items.Add(item =>
{
item.Name = "ProdE5";
});
group.Items.Add(item =>
{
item.Name = "ProdF";
});
group.Items.Add(item =>
{
item.Name = "ProdJ";
});
});
navBarSettings.ClientSideEvents.ItemClick = "onProdNavBarItemClick";
}).GetHtml()
JS
(function () {
var selectedIds;
var itemids;
function onProdInit(s, e) {
AddAdjustmentDelegate(adjustProd);
updateToolbarButtonsState();
}
function onProdSelectionChanged(s, e) {
updateToolbarButtonsState();
}
function adjustProd() {
Prod.AdjustControl();
}
function updateToolbarButtonsState() {
var enabled = Prod.GetSelectedRowCount() > 0;
pageToolbar.GetItemByName("Export").SetEnabled(enabled);
}
function onProdNavBarItemClick(s, e)
{
$.ajax({
Url: ' #Url.Action(e.item.name, "Prod")',
type: 'GET',
}).done(funtion(result) {
if(result.redirectTo)
$('#detailView').html(result);
}).fail(function (jqXHR, exception) {
showError(jqXHR);
})
//switch (e.item.name) {
// case "ProdJ"
I have a menu on my Xamarin app, it is a simple circle which has 3 expendable objects.
Se here
What I want to do is:
to group them together with a Rectangle so it looks more like a flyout menu.
Add function to extend the menu items
Expected result: Here
I have tried to group menu items together through putting Grids inside my main grid, but did not recive expected output..
Here is my code for MenuView.xaml:
<?xml version="1.0" encoding="UTF-8"?>
<ContentView xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:models="clr-namespace:MenuApp.Models;assembly=MenuApp"
xmlns:MenuApp="clr-namespace:MenuApp;assembly=MenuApp"
x:Class="MenuApp.Views.MenuView">
<ContentView.Content>
<ScrollView>
<StackLayout x:Name="menuLayout" >
<ImageButton Source="{MenuApp:ImageResource MenuApp.Images.circle.png}" BackgroundColor="Transparent" x:Name="MainMenu"
Clicked="TapGestureRecognizer_OnTapped" VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand"
Margin="10" WidthRequest="50" HeightRequest="50" ></ImageButton>
</StackLayout>
</ScrollView>
</ContentView.Content>
</ContentView>
Code for MenuView.cs
private void InitializeMenu()
{
LockLandScape();
var children = new List<MenuItem>()
{
new MenuItem { Type = ButtonType.Home},
new MenuItem { Type = ButtonType.Settings},
new MenuItem { Type = ButtonType.Rotate},
}; // get list from Settings.
}
Any ideas are welcome! Thanks.
You could use MasterDetailPage to do that.
1.Create the item of the flyout menu:
public class MenuItem
{
public string Title { get; set; }
public string Icon { get; set; }
public Type TargetType { get; set; }
}
2.Add all the pages into a list: The MainPage, Page1, Page2, Page3 and Page4 are the contentpages which would show when you click the item in the msnu.
public class MenuListData : List<MenuItem>
{
public MenuListData()
{
this.Add(new MenuItem()
{
Title = "Home",
Icon= "diamond_16px.png",
TargetType = typeof(MainPage)
});
this.Add(new MenuItem()
{
Title = "Page1",
Icon = "diamond_16px.png",
TargetType = typeof(Page1)
}) ;
this.Add(new MenuItem()
{
Title = "Page2",
Icon = "diamond_16px.png",
TargetType = typeof(Page2)
});
this.Add(new MenuItem()
{
Title = "Page3",
Icon = "diamond_16px.png",
TargetType = typeof(Page3)
});
this.Add(new MenuItem()
{
Title = "Page4",
Icon = "diamond_16px.png",
TargetType = typeof(Page4)
});
}
}
3.Create the listview for the Menu:
public class MenuListView : ListView
{
public MenuListView()
{
List<MenuItem> data = new MenuListData();
ItemsSource = data;
VerticalOptions = LayoutOptions.FillAndExpand;
BackgroundColor = Color.Transparent;
var cell = new DataTemplate(typeof(ImageCell));
cell.SetBinding(ImageCell.TextProperty, "Title");
cell.SetBinding(ImageCell.ImageSourceProperty, new Binding("Icon"));
cell.SetValue(ImageCell.TextColorProperty, Color.White);
SeparatorVisibility = SeparatorVisibility.Default;
ItemTemplate = cell;
}
}
4.Create the Menu page:
public class MenuPage : ContentPage
{
public ListView Menu { get; set; }
public MenuPage()
{
Title = "Menu";
BackgroundColor = Color.FromHex("FF8CB9");
Menu = new MenuListView();
var layout = new StackLayout
{
Spacing = 0,
VerticalOptions = LayoutOptions.FillAndExpand,
Padding = 5
};
layout.Children.Add(Menu);
Content = layout;
}
}
5.Create the RootPage as MasterDetailPage:
public class RootPage : MasterDetailPage
{
MenuPage menuPage;
public RootPage()
{
menuPage = new MenuPage();
menuPage.Menu.ItemSelected +=
(sender, e) => NavigateTo(e.SelectedItem as MenuItem);
Master = menuPage;
Detail = new NavigationPage(new MainPage());
MasterBehavior = MasterBehavior.Popover;
}
void NavigateTo(MenuItem menu)
{
if (menu == null)
return;
Page displayPage = null;
switch (menu.TargetType.Name)
{
case "Page1":
case "Page2":
case "Page3":
case "Page4":
default:
displayPage = (Page)Activator.CreateInstance(menu.TargetType);
break;
};
try
{
Detail = new NavigationPage(displayPage);
}
catch (Exception ex)
{
App.Current.MainPage.DisplayAlert("ERRO", "Erro " + ex.Message, "OK");
}
menuPage.Menu.SelectedItem = null;
IsPresented = false;
}
}
OutPut:
I have a view component, EventsViewComponent, which is loaded in my Events view index.cshtml using the following lines of code:
<div id="events">
#await Component.InvokeAsync("Events", new { showPrevious = Model.ShowPrevious, showUpcoming = Model.ShowUpcoming })
</div>
I have two checkboxes added like this:
#Html.CheckBoxFor(m => m.ShowPrevious, new { id = "cbShowPrevious", onchange = "ReloadEvents()" })
#Html.CheckBoxFor(m => m.ShowUpcoming, new { id = "cbShowUpcoming", onchange = "ReloadEvents()" })
ReloadEvents() refers to a Javascript function in which I was hoping to refresh the EventsViewComponent with an Ajax call something like:
function ReloadEvents() {
$.ajax({
url: '#Url.Action("ReloadEvents", "Events")',
data: {
showPrevious: document.getElementById("cbShowPrevious").checked,
showUpcoming: document.getElementById("cbShowUpcoming").checked
},
success: DoThis()
})
}
function DoThis() {
const eventsDiv = document.getElementById('events');
eventsDic.innerHTML = //HTML from EventsViewComponent
}
But I don't seem to be able to get the HTML from the EventsViewComponent.
I have written the Default.cshtml for EventsViewComponent like this:
#{
List<Event> events = ViewData["Events"] as List<Event>;
if (events.Count > 0)
{
<table>
//event data from the model
</table>
}
}
The InvokeAsync method in EventsViewComponent is being hit, as is the ReloadEvents method in EventsController but I'm obviously misunderstanding something as I don't seem to be able to update the EventsViewComponent.
Please could someone advise if this is possible and how to go about achieveing it?
To get the HTML from the EventsViewComponent,you need to change like below:
success: function (data) {
$("#events").html(data);
}
Here is a whole working demo like below:
1.Model:
public class Event
{
public bool ShowPrevious { get; set; }
public bool ShowUpcoming { get; set; }
public string Data { get; set; }
}
2.ViewComponent:
public class EventsViewComponent : ViewComponent
{
List<Event> data = new List<Event>() {
new Event(){ ShowPrevious=true,ShowUpcoming=false,Data="aaa"},
new Event(){ ShowPrevious=false,ShowUpcoming=true,Data="bbb"},
new Event(){ ShowPrevious=false,ShowUpcoming=true,Data="ccc"},
};
public IViewComponentResult Invoke(bool showPrevious,bool showUpcoming)
{
if (showPrevious == true && showUpcoming == true)
{
ViewData["Events"] = data;
}
else if (showPrevious)
{
ViewData["Events"] = data.Where(u => u.ShowPrevious == true).ToList();
}
else if(showUpcoming)
{
ViewData["Events"] = data.Where(u => u.ShowUpcoming == true).ToList();
}
return View();
}
}
3.Controller:
public class HomeController : Controller
{
public IActionResult ReloadEvents(bool showPrevious, bool showUpcoming)
{
return ViewComponent("Events", new { showPrevious = showPrevious, showUpcoming = showUpcoming });
}
public IActionResult Index()
{
var model = new Event() { ShowPrevious = true, ShowUpcoming = true };
return View(model);
}
}
4.Index.cshtml:
#model Event
#Html.CheckBoxFor(m => m.ShowPrevious, new { id = "cbShowPrevious", onchange = "ReloadEvents()" })
#Html.CheckBoxFor(m => m.ShowUpcoming, new { id = "cbShowUpcoming", onchange = "ReloadEvents()" })
<div id="events">
#await Component.InvokeAsync("Events", new { showPrevious = Model.ShowPrevious, showUpcoming = Model.ShowUpcoming })
</div>
#section Scripts
{
<script>
function ReloadEvents() {
$.ajax({
url: '#Url.Action("ReloadEvents", "Home")',
data: {
showPrevious: document.getElementById("cbShowPrevious").checked,
showUpcoming: document.getElementById("cbShowUpcoming").checked
},
success: function (data) {
$("#events").html(data);
}
})
}
</script>
}
5.Default.cshtml(the view component Razor view):
#model Event
#{
List<Event> events = ViewData["Events"] as List<Event>;
if (events.Count > 0)
{
<table>
<tr>
<th>ShowPrevious</th>
<th>ShowUpcoming</th>
<th>Data</th>
</tr>
<tbody>
#foreach (var item in events)
{
<tr>
<td>#item.ShowPrevious</td>
<td>#item.ShowUpcoming</td>
<td>#item.Data</td>
</tr>
}
</tbody>
</table>
}
}
Result:
I have implemented such solution in one of my projects, check it out -> Refreshing .Net core MVC ViewComponent over AJAX
First I would like to say I have been trying to get this to work for over a year. I have tried a majority of the tutorials offered online. I ended up literally copying a template I found online and I still can't get this to work. I have a bunch of files I'll post the main two. Can someone please tell my how to fix this error message? I don't mean to plagiarize, If I can just get this to work, I can work on my own based off a working example.
MainGameFile.as
package {
import com.adobe.serialization.json.JSON;
import com.facebook.graph.Facebook;
import flash.display.Loader;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.IOErrorEvent;
import flash.events.MouseEvent;
import flash.net.URLRequest;
public class FlashMobileWeb extends Sprite {
protected static const APP_ID:String = "647743112027883"; //Your App Id
protected static const APP_URL:String = "https://localhost:3000/";
protected var profilePic:Loader;
public function FlashMobileWeb() {
var accessToken:String;
if (loaderInfo.parameters.accessToken != undefined) {
accessToken = String(loaderInfo.parameters.accessToken); //get
the token passed in index.php
}
Facebook.init(APP_ID, onInit, null, accessToken);
loginBtn.addEventListener(MouseEvent.CLICK, handleLoginClick, false, 0, true);
callBtn.addEventListener(MouseEvent.CLICK, handleCallClick, false, 0, true);
profilePic = new Loader();
profilePic.contentLoaderInfo.addEventListener(Event.INIT, handleProfilePicInit, false, 0, true);
profilePic.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, handleProfilePicIOError, false, 0, true);
profileHolder.addChild(profilePic);
}
protected function onInit(response:Object, fail:Object):void {
if (response) {
outputTxt.appendText("Logged In\n");
loginBtn.label = "Logout";
} else {
outputTxt.appendText("Click to Login\n");
loginBtn.label = "Login";
}
}
protected function handleLoginClick(event:MouseEvent):void {
if (loginBtn.label == "Login") {
var redirectUri:String = APP_URL; //Your App URL as specified in facebook.com/developers app settings
var permissions:Array = ["user_photos", "user_location"];
Facebook.mobileLogin(redirectUri, "touch", permissions);
} else {
outputTxt.appendText("LOGOUT\n");
Facebook.mobileLogout(APP_URL); //Redirect user back to your app url
}
}
protected function onLogout(response:Object):void {
loginBtn.label = "Login";
outputTxt.text = "";
}
protected function handleCallClick(event:MouseEvent):void {
Facebook.api("/me", onApiCall);
}
protected function onApiCall(response:Object, fail:Object):void {
if (response) {
outputTxt.appendText("RESPONSE:\n" + JSON.encode(response) + "\n");
var req:URLRequest = new URLRequest(Facebook.getImageUrl(response.id, "square"));
profilePic.load(req);
profileHolder.nameTxt.text = response.name + "\n";
if (response.location != null) { profileHolder.nameTxt.appendText(response.location.name); }
}
}
protected function handleProfilePicInit(event:Event):void {
profilePic.x = 1;
profilePic.y = profileHolder.height - profilePic.height >> 1;
}
protected function handleProfilePicIOError(event:IOErrorEvent):void {
outputTxt.appendText("Error Loading Profile Pic\n");
}
}
}
AbstractFacebook.as
package com.facebook.graph.core {
import com.facebook.graph.data.FacebookSession;
import com.facebook.graph.net.FacebookRequest;
import flash.net.URLRequestMethod;
import flash.utils.Dictionary;
public class AbstractFacebook {
protected var session:FacebookSession;
protected var openRequests:Dictionary;
public function AbstractFacebook():void {
openRequests = new Dictionary();
}
protected function api(method:String,
callback:Function = null,
params:* = null,
requestMethod:String = 'GET'
):void {
method = (method.indexOf('/') != 0) ? '/'+method : method;
if (session != null) {
if (params == null) { params = {}; }
params.access_token = session.accessToken;
}
var req:FacebookRequest = new FacebookRequest(
FacebookURLDefaults.GRAPH_URL,
requestMethod
);
openRequests[req] = callback;
req.call(method, params, handleRequestLoad);
}
protected function handleRequestLoad(target:FacebookRequest):void {
var resultCallback:Function = openRequests[target];
if (resultCallback === null) {
delete openRequests[target];
}
if (target.success) {
var data:Object = ('data' in target.data) ? target.data.data : target.data;
resultCallback(data, null);
} else {
resultCallback(null, target.data);
}
delete openRequests[target];
}
protected function callRestAPI(methodName:String,
callback:Function = null,
values:* = null,
requestMethod:String = 'GET'
):void {
if (values == null) { values = {}; }
values.format = 'json';
if (session != null) {
values.access_token = session.accessToken;
}
var req:FacebookRequest = new FacebookRequest(
FacebookURLDefaults.API_URL,
requestMethod
);
openRequests[req] = callback;
req.call('/method/' + methodName, values, handleRequestLoad);
}
protected function fqlQuery(query:String, callback:Function):void {
callRestAPI('fql.query', callback, {query:query});
}
protected function deleteObject(method:String, callback:Function = null):void {
var params:Object = {method:'delete'};
api(method, callback, params, URLRequestMethod.POST);
}
protected function getImageUrl(id:String, type:String = null):String {
return FacebookURLDefaults.GRAPH_URL
+ '/'
+ id
+ '/picture'
+ (type != null?'?type=' + type:'');
}
}
}
I will display a view, when I click on checkbox
I tried like this, but not work,
I need your help to fix the problem
Models:
public class DisplayData
{
public bool ID { get; set; }
public DisplayData(bool ID)
{
this.ID = ID;
}
}
public class Element
{
public string Descripcion { get; set; }
}
HomeController:
public ActionResult Index()
{
DisplayData Display = new DisplayData(false);
return View(Display);
}
Index.cshtml:
#model AppTwitter.Models.DisplayData
<script src="#Url.Content("~/Scripts/myCheckbox.js")" type="text/javascript"></script>
#Html.CheckBoxFor(
x => x.ID,
new {
data_url = Url.Action("PartialDemo", "PartialDemo"),
id = "mycheckbox"
}
myCheckbox.js:
$(function () {
$('#mycheckbox').change(function () {
var data = {};
data[$(this).attr('name')] = $(this).is(':checked');
$.ajax({
url: $(this).data('url'),
type: 'POST',
data: data,
success: function (result) {
}
});
});
});
PartialDemoController.cs
public ActionResult PartialDemo()
{
var element = new Element();
element.Descripcion = "Descripcion";
return View(element);
}
PartialDemo.cshtml:
#model AppTwitter.Models.Element
<div class="editor-label">
#Html.LabelFor(model => model.Descripcion )
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Descripcion )
#Html.ValidationMessageFor(model => model.Descripcion )
</div>
Thanks,
#Victor, Now i got the issue. The id that you are assigning to checkbox doesn't get worked because you are using #Html.CheckBoxFor(x => x.ID). in this case the id of checkbox is generating dynamically hence "mycheckbox" doesn't get worked. So Instead assigning a id assign a class i.e
#Html.CheckBoxFor(
x => x.ID,
new {
data_url = Url.Action("PartialDemo", "PartialDemo"),
#class = "mycheckbox"
}
)
and in javascript use below:
$(function () {
$('.mycheckbox').click(function () {
// your existing stuff
});
});
Hope this will solve the problem