Getting a page view element from a model class - nativescript

I've got a model class and would like to get access to a ui element.
frameModule.topmost().getViewById("id") or
frameModule.topmost().page.getViewById("id")
don't work.

As I understand what you need, I hope this solution would help.
In XML, assuming that you have UI Element with an ID. You will get it in the controller. For example:
In page.xml:
<Label id="test"/>
In the binding object class in page-view-model.js, create a property that has type of label:
var labelModule = require("ui/label");
var Label = labelModule.Label;
class Someclass extends Observable {
public label: Label;
}
In page.js:
function pageLoaded(args) {
var page = args.object;
var myLabel = page.getViewById("test");
var context = new Someclass();
page.bindingContext = context;
context.label = myLabel;
}

There are many ways to get a reference to the Page object. The documentation is a good reference to learn about them: https://v7.docs.nativescript.org/ui/components/page#page-reference
To answer you question, the usual way to get a reference to the Page object inside a view model class is by using the EventData passed to each event like a tap event when a Button is tapped.
onButtonTap(args: EventData) {
const button = args.object as Button;
const page = button.page;
// ...
}

Related

How change whole view without calling navigate()?

I need dynamically change whole view to another (for example, root layout should be changed to DockLayout), but without using Frame.navigate() method.
How do this?
Other question is about View.load() method. What use cases of this method?
const view = parse(`<StackLayout><Button tap="{{ onButtonTap }}" text="Tap me!"/></StackLayout>`);
class ViewModel extends Observable {
public onButtonTap(args: EventData) {
// need to change whole view to another here (for example, root layout should be DockLayout now)
// but without using Frame.navigate() method
// How do this?
}
}
app.run({
create: () => {
view.bindingContext = new ViewModel();
return view;
}
});
You could use builder for that.
const builder = require('tns-core-modules/ui/builder');
const view = builder.parse(`<StackLayout><Button tap="{{ onButtonTap }}" text="Tap me!"/></StackLayout>`);
view.bindingContext = myBindingContext;
// If you want to replace everything in Page
page.content = view;
Or
// If you want to add it to a parent layout
parentStackLayout.addChild(view);
Edit: If you want to replace your root view itself, then you have to use the _resetRootView method on application module.
const create = () => {
const view = builder.parse(`<StackLayout><Button tap="{{ onButtonTap }}" text="Tap me!"/></StackLayout>`);
view.bindingContext = myBindingContext;
return view;
};
application._resetRootView({
create: create
});

How can we add loader in clarity framework in div as we can add in Datagrid attribute [clrDgLoading]="loading" to add loader

How can we add loader in clarity framework in div tag as we can add in Datagrid attribute [clrDgLoading]="loading" to add loader?
Clarity has a spinner component, the detailed documentation is available here: https://vmware.github.io/clarity/documentation/spinners
Set the [clrDgLoading] property in template like below.
<clr-datagrid [clrDgLoading]="loading">
In Component.ts initialize the "loading" property to true. Then after data loaded from the data service, set the "loading" property to false.
export class Component implements OnInit {
loading = true;
constructor(
private dataService: DataService,
) {}
ngOnInit(): void {
this.dataService
.getData()
.subscribe((data) => {
// your code
this.loading = false;
});
}

Kendo listview - clicking elements that have been moved between listviews yields a different sender object structure

I'm seeing an issue where if I add new options to my listbox, the event.sender no longer has the same object structure when I click those newly moved options in their new listview.
I use an ajax event to bind data to the Kendo listview (this is in a method that gets triggered on document ready):
var myListBoxId = 'myListBoxHtmlId';
$.post('myUrl/myController/controllerMethod', dataToPost)
.done(function (response, status, jqxhr) {
$('#' + myListBoxId').kendoListBox({
dataSource: response.myListProperty,
connectWith: theOtherListBoxId,
dropSources: [theOtherListBoxId],
toolbar: {
position: "right",
tools: ["transferAllFrom", "transferAllTo",
"transferFrom", "transferTo"]
},
change: function (event) {
myJavascriptMethod(event);
},
dataTextField: 'propertyNameInObjectInMyPropertyList',
dataValueField: 'anotherPropertyNameInObjectInMyPropertyList'
});
You can see that it binds the 'myJavascriptMethod(event)' as the change event handler.
Here is how I'm accessing the event data in myJavascriptMethod(event):
myJavascriptMethod(event){
var selectedText = event.sender._target[0].innerHTML;
}
The problem is that if I modify the options (I'm using the 'transferFrom' and 'transferTo' to transfer options between two kendo listviews), the event.sender._target is null. I'm having difficulty figuring out what I should key onto that would work in all cases.
In addition to the example code above, I found this, which has more docs on listviews for .net-core:
https://github.com/telerik/kendo-ui-core/blob/master/docs/api/javascript/ui/listbox.md
When changing the return object in the C# List I was binding the datasource to in the response to the AJAX method, I also noticed that it doesn't really matter what type it is, as long as the property names match the listview's dataTextField and dataValueField.
The solution to properly getting the selected item from the listview that would work with both the originally bound options and options that have been moved between listviews was this (no changes required to the listview as shown in the question):
//reformatted this as Javascript
//for typescript it was of this format:
//static myTypeScriptEvent(event){
function myJavascriptEvent(event){
//This line was the fix / is key to the question:
var dataItem = event.sender.dataItem(event.sender.select());
}
Here's a minimum example of the AJAX method that binds the listview. Include a call to this method in the document.ready function (thingId is the id of some object that will have sub objects in a list which will then be bound to the listview). In my case, I'm using typescript, you may have to convert some of it to basic javascript as your needs require (it's pretty close, but it may need some slight changes - as indicated by the '$' characters, you'll also need to include jquery for this):
function bindListView( id: thingId ) {
var dataToPost = {
id: id
};
$.post('myUrl/myController/controllerMethod', dataToPost)
.done(function (response, status, jqxhr) {
$('#' + myListBoxId').kendoListBox({
dataSource: response.myList,
connectWith: theOtherListBoxId,
dropSources: [theOtherListBoxId],
toolbar: {
position: "right",
tools: ["transferAllFrom", "transferAllTo",
"transferFrom", "transferTo"]
},
change: function (event) {
myJavascriptMethod(event);
},
dataTextField: 'Id',
dataValueField: 'Name'
}); //end of listView bind
}); //end of $.post().done() function
} //end of bindListView() function
And finally, here's what your controller method should be like for the above:
I'll include a pseudo class and fill it with data. The return object is the "response" variable, and whatever your list names are is accessed like this in the datasource: response.listname. Finally, whatever the object types are in those lists, the property names on those objects just have to match the dataTextField and dataValueField of the listview.
//This will be the type of object I'm putting into the list that's
//going into the object I'm returning
public MyClass {
public int Id {get; set;} //so we change the listview's dataValueField to Id
public string Name {get; set;} //we change the listview's dataTextField to Name
}
//And this will be the overall type of object that will hold the list, will get
//returned, becoming the "response" in the AJAX .done:
public class MyReturnObject {
public List MyList {get; set;} //so we change the ListView's datasource to response.MyList
//It may become myList, so you may need to look at the response object in the debugger.
}
[HttpPost]
public JsonResult MyControllerMethod(int id)
{
//Create the return object, give it a new list, add things to the list
//so the ListView can be bound:
var myReturnObject = new MyReturnObject();
myReturnObject.Mylist = new List();
var object1 = new MyClass { Id = 1, Name = "Hello World" };
var object2 = new MyClass { Id = 2, Name = "Hello again" };
myReturnObject.MyList.Add(object1);
myReturnObject.MyList.Add(object2);
//Convert the return object and everything in it to Json and return it to
//The AJAX method:
return Json(myReturnObject);
}

Edit button with comments using MooTools/AJAX

So I'm using a PHP API to interact with, to build a forum using MooTools. I can get comments from my database and add comments, but I want to inject an edit button to coincide with each comment.
I inject the comments using:
function domReady() {
$('newComment').addEvent('submit', addComment);
}
function addComment(e){
e.stop();
var req = new Request({
url:'control.php?action=insertPost',
onSuccess:addajaxSuccess
}).post(this);
}
function addajaxSuccess(idNo) {
new Element('span',{
'text':'Post successful.'
}).inject($(newComment));
$('commentList').empty();
domReady();
}
I want to attach an edit button to each comment injected, and add an event listener on the button to change the comment into a textarea for editting, with an update button.
Any ideas?
If you want to bind a global events to a dynamic content you have better look into Element Delegation In mootools.
Basically it's give you the ability to bind event to some container and "listen" to events of that children container base on selectors. I made you a little example here:
http://jsfiddle.net/xwpmv/
mainContainer.addEvents({
'click:relay(.mt-btn)': function (event, target) {
var btn = target;
if(btn.get('value') == 'Edit'){
btn.set('value','Done Editing');
var content = btn.getPrevious();
content.setStyle('display','none');
var textarea = new Element('textarea').set('text',content.get('text'));
textarea.inject(btn,'before');
}
else{
btn.set('value','Edit');
var textarea = btn.getPrevious();
var new_value = textarea.get('value');
textarea.destroy();
var content = btn.getPrevious();
content.set('text',new_value);
content.setStyle('display','block');
}
}
});
Here you can see the mainContainer listen to the click event of every element who has mt-btn class (the buttons)
You have several errors in your code but maybe it is just an example so I didn't relate to it.

Ember js: parentViewDidChange doesn't get triggered

If have a little game where images have to be dragged on the right hotspots of a larger image.
The little images are inside a containerView, the hotspots also are ContainerViews.
When i drop the images on a hotspot i use the following code in my drag-n-drop mixin to move the image in the dom:
Player.Droppable = Ember.Mixin.create({
drop: function(event) {
//get the view that was dragged
var viewId = event.originalEvent.dataTransfer.getData('Text');
var view = Ember.View.views[viewId];
//log the parent-view: App.AnswerListView
console.log(view.get('parentView').constructor);
//detach the view from the original containerView
var parentView = view.get('parentView');
parentView.removeObject(view);
//attach it to the hot-spot-containerview
this.addObject(view);
//logging this gives a different result: App.HotspotView
console.log(view.get('parentView').constructor);
event.preventDefault();
return false;
}
});
The view i'm dragging is an App.AnswerView. What i'm expecting from the docs is that the function parentViewDidChange on the AnswerView is triggered, but that doesn't happen:
App.AnswerView = Ember.View.extend(App.Draggable, {
templateName: "answer",
classNameBindings: [':answer', 'this.content.isSelected:selected'],
click: function(evt){
this.get('controller').send('answerClicked', this.content);
},
parentViewDidChange: function(){
this.get('controller').send('answerMoved', this.content);
},
});
The docs say: Called when the parentView property has changed. In my case, it is changed. Is this a bug, or am I missing something here?
TIA
This issue was a bug and got resolved in the 1.0.0 final
https://github.com/emberjs/ember.js/issues/2423
pushObject and removeObject are methods, inherited from the Ember.MutableArray Mixin, that the Ember.ContainerView extends. If you look at Ember's source code for ContainerView (https://github.com/emberjs/ember.js/blob/v1.0.0-rc.2/packages/ember-views/lib/views/container_view.js#L15), you will see that ContainerView does not override those methods, thus they only manipulate its childViews array, not the view's parent view.
You should find methods that manipulate the '_parentView' property here instead: (https://github.com/emberjs/ember.js/blob/v1.0.0-rc.2/packages/ember-views/lib/views/view.js#L2018) - in the Ember.View's implementation.
So in short, use:
removeChild instead of removeObject, to delete a child view from your ContainerView
createChildView + pushObject instead of 'addObject', if you want to add a new child view to a ContainerView.
Example Code:
Player.Droppable = Ember.Mixin.create({
drop: function(event) {
//get the view that was dragged
var viewId = event.originalEvent.dataTransfer.getData('Text');
var view = Ember.View.views[viewId];
//log the parent-view: App.AnswerListView
console.log(view.get('parentView').constructor);
//detach the view from the original containerView
var parentView = view.get('parentView');
parentView.removeChild(view);
//attach it to the hot-spot-containerview
this.createChildView(view);
this.pushObject(view);
//logging this gives a different result: App.HotspotView
console.log(view.get('parentView').constructor);
event.preventDefault();
return false;
}
});

Resources