Xamarin forms making simple menu - javascript

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:

Related

Javascript does not update value of a blazor component

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.

Refresh ViewComponent in ASP.Net Core MVC View

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

Iterate on a JSON in JavaScript Asp.net

I have following data that I have serialized as JSON from my code behind file.
public class PieModel {
public string label { get; set; }
public double data { get; set; }
}
var data = new List<PieModel> {
new PieModel { label = "Pending", data = 10d }
new PieModel { label = "New", data = 40d }
new PieModel { label = "Overdue", data = 50d }
};
hdnData.Value = new JavaScriptSerializer().Serialize(data);
I read this serialized data in JavaScript like this
var tempHdnData = $("#hdnData");
But now I want to iterate on tempHdnData and get label and data members separately in JavaScript code. How can I achieve that?
You could write your code like this in the code behind:
protected List<PieModel> GetData() {
return new List<PieModel> {
new PieModel { label = "Pending", data = 10d }
new PieModel { label = "New", data = 40d }
new PieModel { label = "Overdue", data = 50d }
};
}
And in your webform:
var tempHdnData = <%= new JavaScriptSerializer().Serialize(GetData()) %>
Now you can write
$.each(tempHdnData, function (_, data) {
console.log(data)
})

Webmethod is not fired by jsTree

I m trying to call web method from jsTree but unable to call it. can someone please help me out to get this resolved.
my jsTree function is:-
$('#tree').jstree({
"json_data": {
"ajax": {
"type": "POST",
"dataType": "json",
"async": true,
"contentType": "application/json;",
"opts": {
"method": "POST",
"url": "../../SurveyReport/Metrics.aspx/GetAllNodes11"
},
"url": "../../SurveyReport/Metrics.aspx/GetAllNodes11",
"data": function (node) {
if (node == -1) {
return '{ "operation" : "get_children", "id" : -1 }';
}
else {
//get the children for this node
return '{ "operation" : "get_children", "id" : ' + $(node).attr("id") + ' }';
}
},
"success": function (retval) {
alert('Success')
return retval.d;
},
"error": function (r) {
alert(r.attr);
alert('error');
}
}
},
"plugins": ["themes", "json_data"]
});
And web method and data file is:-
[WebMethod]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public static List<G_JSTree> GetAllNodes11(string id)
{
if (id != "-1") //-1 means initial load else async loading of children
{
if (id == "10")
//Add 3 children to parent node with id=10.
return AddChildNodes(10, 3, "xxxx");
else
return new List<G_JSTree>();
}
List<G_JSTree> G_JSTreeArray = new List<G_JSTree>();
//Creating the JsTree data
//In live scenarios this will come from db or Web Service
//Add 5 root nodes
G_JSTreeArray.AddRange(AddChildNodes(0, 5, ""));
//Add 4 children to 3rd root node
//The third node has id=30
//The child nodes will have ids like 301,302,303,304
G_JSTreeArray[3].children = (AddChildNodes(30, 4, G_JSTreeArray[3].data)).ToArray();
//Add 5 children to level1 Node at id=302
G_JSTreeArray[3].children[1].children = (AddChildNodes(302, 4, G_JSTreeArray[3].children[1].data)).ToArray();
return G_JSTreeArray;
}
private static List<G_JSTree> AddChildNodes(int _ParentID, int NumOfChildren, string ParentName)
{
List<G_JSTree> G_JSTreeArray = new List<G_JSTree>();
int n = 10;
for (int i = 0; i < NumOfChildren; i++)
{
int CurrChildId = (_ParentID == 0) ? n : ((_ParentID * 10) + i);
G_JSTree _G_JSTree = new G_JSTree();
_G_JSTree.data = (_ParentID == 0) ? "root" + "-Child" + i.ToString() : ParentName + CurrChildId.ToString() + i.ToString();
_G_JSTree.state = "closed"; //For async to work
_G_JSTree.IdServerUse = CurrChildId;
_G_JSTree.children = null;
_G_JSTree.attr = new G_JsTreeAttribute { id = CurrChildId.ToString(), selected = false };
G_JSTreeArray.Add(_G_JSTree);
n = n + 10;
}
return G_JSTreeArray;
}
public class G_JSTree
{
public G_JsTreeAttribute attr;
public G_JSTree[] children;
public string data
{
get;
set;
}
public int IdServerUse
{
get;
set;
}
public string icons
{
get;
set;
}
public string state
{
get;
set;
}
}
public class G_JsTreeAttribute
{
public string id;
public bool selected;
}
}
I want to load the tree in an async fashion from a webmethod in an asp.net page.
Thanks in advance.
I use this Code Successfully By add this Complete Reference :
[System.Web.Services.WebMethod]
[System.Web.Script.Services.ScriptMethod(ResponseFormat = System.Web.Script.Services.ResponseFormat.Json)] //ResponseFormat.Json)]
public static List<GG_JSTree> GetAllNodes11(string id)
{......}

checkbox with javascript && jQuery

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

Categories