Could you please help me with MVC implementation with enyojs framework
The current goal is to implement N -panels (displays, windows) for TV application which would be changed after button was pressed (channel switch for instance). It looks just like simple redirect to new URL (or controller's action) in web. So, we want to re-render views and parts of views and update windows(panels) using strategy of keeping just 2 displays at the same time (current and next we go with animation). I learned some examples of MVC with enyo from other topics here, but that implementations of MVC but some questions are still exist.
Problem: how to implement in enyo the particle updating of the view with new data from controller ?
//--- app.js
enyo.kind({
name: "my.Application",
kind: "enyo.Application",
view: "Index", // default start view
controllers: [ // I use 2.3 version and know about this rudiment property.
{name: "homeController", kind: "HomeController"}
],
viewChanged : function() {
this.inherited(arguments);
app.render(); // this updates the view. Changes from index to edit and back.
}
});
enyo.ready(function () {
app = new my.Application({name: "app"});
});
//------ controller.js + IndexView.js + editview.JS
enyo.kind({
name : "IndexView",
kind: "enyo.View",
components: [
{content: "HelloWorld, This is Index"},
{content: "This is the Index view"},
{kind: "moon.ToggleButton", content: "Show Edit", ontap: "buttonTapped"}
],
// redirect to Edit View
buttonTapped: function(sender, event){
app.controllers.homeController.Edit("message(model) to Edit View");
}
});
enyo.kind({
name : "EditView",
kind: "enyo.View",
message: "no msg",
components: [
{name: "headWithId", content: "Hello! This is EDIT."},
{content: "This is the Edit view"},
{kind: "moon.ToggleButton", content: "Show Index", ontap: "buttonTapped"}
],
bindings: [
{from: ".message", to:".$.headWithId.content"}
],
// redirect to Index View
buttonTapped: function(sender, event){
app.controllers.homeController.Index();
}
});
enyo.kind({
name : "HomeController",
kind: "enyo.Controller",
Index : function(){
app.set("view", new IndexView()); // this code updates the view of app, but maybe there is a better way to do it?
},
Edit : function(msg){
app.set("view", new EditView({message: msg}));
}
});
The previous code works find. There some question in comments. But how to implement such situation, then I don't want to rerender all the divs of the view, but just particle content (for example, leave the header and update the content):
// ----- baselayoutview.js
enyo.kind({
name : "BaseLayout",
kind: "enyo.ViewController", // or enyo.View... what is better?
components: [
{content: "this content of the View never changes"},
// next content should be changed. It's for renderTarget
{name: "RenderContentSection"} // How to render new content form Index or Edit view here?
]
});
// ----- app.js
enyo.kind({
name: "my.Application",
kind: "enyo.Application",
view: "BaseLayout", // We set this base layout view and expect the it will fill it's content by itself
controllers: [
{name: "homeController", kind: "HomeController"}
],
viewChanged : function() {
this.inherited(arguments);
app.render("RenderContentSection"); // I think it would not be working any more.. but what it the best way to do it? How to update BaseLayout view's RenderContentSection ?
}
});
You should not be calling app.render() to re-render your application. As you say, you don't want to re-render the whole thing each time. Are you stuck on Enyo 2.3 or can you update to a more recent version? Controllers have been largely deprecated, for one.
I suggest taking a look at the Panels component. You can place a Panels component within your area that changes and navigate to a panel and push whatever content you want into that panel. You individual sections would be Panel components and you can push and pop those as needed. If you need to replace the panel.
If you really want to do it that way, you can modify your BaseLayout component so that it uses createComponent() to create whichever partial view you want.
enyo.kind({
name : "BaseLayout",
// This can be just a plain enyo.Control
components: [
{content: "this content of the View never changes"},
// next content should be changed. It's for renderTarget
{name: "renderContentSection"} // How to render new content form Index or Edit view here?
],
replacePartial: function(partial) {
this.$.renderContentSection.destroyClientControls();
this.$.renderContentSection.createComponent({kind: partial});
this.$.renderContentSection.render();
}
});
Here's a fiddle showing that off: http://jsfiddle.net/RoySutton/LhjLv6hy/
You could create a new control with a 'chrome' controls and a client area that controls get rendered into, but this is pretty simple. Still, take a look at Panels. It's what they were designed for.
Related
Let's say I have my routes defined in my manifest.json like this
rootView: "sap.ui.core.sample.TargetsStandalone.targetsApp.view.App",
routing: {
config: {
targetsClass: "sap.m.routing.Targets",
viewPath: "sap.ui.core.sample.TargetsStandalone.targetsApp.view",
controlId: "rootControl",
controlAggregation: "pages",
viewType: "XML"
},
targets: {
page1: {
viewName: "View1",
viewLevel: 0
},
page2: {
viewName: "View2",
viewLevel: 1
}
}
}
Is there a way to retrieve the view references from the component(getOwnerComponent). What I want to do is, on the first controller I want to get a reference of label on "View2". It seems like there is no reference to the second view until I navigate to it. Is there a way to get the a reference to another view and its elements before I navigate to it?
When you navigate to a view, the runtime instantiate it. Before that, there is no view. You can even see in the network trace how the XML file of certain view is downloaded once you navigate to it for the first time, but not before.
I have a page with a route #grants/{grantId} that contains tabbed content. I want each tab to be accessible by route #grants/{grantId}/{tabId}.
So I've setup router like below and i works, however when I switch tabs (e.g. when i go from #grants/123/tab1 to #gratns/123/tab2) the conent of the page gets rebuild (invalidated). How can I prevent that?
var oRouter = new sap.ui.core.routing.Router([
{
pattern: "grants",
name: "_grants",
view: "grants.Grants",
viewType: sap.ui.core.mvc.ViewType.HTML,
viewId: "grants",
targetControl: "theContent",
targetAggregation: "content",
clearTarget: true,
subroutes: [
{
pattern: "grants/{id}/:period:",
name: "_grantPortfolio",
view: "grants.GrantPortfolio",
viewType: sap.ui.core.mvc.ViewType.HTML,
viewId: "grantPortfolio",
targetControl: "theContent",
targetAggregation: "content",
clearTarget: true
}]
}]);
As far as I understand your question I would suggest to implement a special logic in your controller's route match callback. There you can check - depending on the event parameter - which data needs to be loaded and which data have been loaded already. For more specific hints a running example would be required.
I want to render a view which I create when the button on another view is clicked.
Here is my controller code, and I am following the MVC architecture
Ext.define('demo.controller.LoginController' , {
extend: 'Ext.app.Controller',
config: {
refs:{
loginAction: 'button[action=login]'
},
control:{
loginAction: {
tap:'loginProcess'
}
}
},
loginProcess:function(button,e,opts){
// Render View here
}
});
I have searched and I came across getMainView().push() and Ext.ViewPoart.add() but it's not working. According to the MVC pattern how should call this view from a controller?
EDIT
code of profilecontainer
Ext.define('demo.view.ProfileContainer',{
extend:'Ext.Panel',
xtype:'profilecontainer',
requires: [
'Ext.Label'
],
config: {
items:[{
xtype:'label',
html:'hi'
}]
}
});
Both of the ways you have tried should work, if you set them up correctly.
First, getMainView().push(newView) will work if mainView is an Ext.navigation.View. See the docs for this method here: http://docs.sencha.com/touch/2.2.1/#!/api/Ext.navigation.View-method-push
You can also use Ext.Viewport.setActiveItem(newView), assuming you have no typos (your post says ViewPoart). (Ext.Viewport.add will add the panel to the Viewport, but not set it as the active Card in the layout)
If neither of these are working, then you probably are not configuring your controller correctly. If that is the case, ensure that your loginProcess method is being called. If it is not, then your selector, button[action=login], is not correct.
Sometimes we use one store for few views(list, carousel,dataviews) and when we refresh(load, filter) store data, dom of all view that use this store will be rebuild, but some views is not displayed in this time, and may be will not show with these data. How we can refresh list dom only if it displayed, not every time when it store refresh?
Issue examle
Ext.define("Test.view.Main", {
extend: 'Ext.tab.Panel',
config: {
tabBarPosition: 'bottom',
items: [ ]
},
constructor : function(){
this.callParent(arguments);
var store = Ext.create('Ext.data.Store',{
data :[
{title : 'One'},
{title : 'Two'},
{title : 'Three'}
]
}),
firstList = Ext.create('Ext.List',{
title : 'tab1',
store : store,
itemTpl : '{title}',
onItemDisclosure : function(){
store.add({title : 'Four'});
}
}),
secondList = Ext.create('Ext.List',{
title : 'tab2' ,
store : store,
itemTpl : '{title}'
}),
thirdList = Ext.create('Ext.List',{
title : 'tab3',
store : store,
itemTpl : '{title}'
});
this.add([
firstList,
secondList,
thirdList
]) ;
}
});
When tap on item in the first list, in store will be added new item. And dom of all list will be change although second and third list not displayed
I see one option. Create one main store and create separate stores for each views. And when view show fill it store from Main store. But it look not good. Any other ideas?
As far as I know, there is no "out-of-the-box" solution. The docs say that the refresh event is preventable, but I haven't tested that theory.
One other idea would be to look at the dataview source and override parts of it.
The starting point would probably be to look at the store event hooks that you can find there:
storeEventHooks: {
beforeload: 'onBeforeLoad',
load: 'onLoad',
refresh: 'refresh',
addrecords: 'onStoreAdd',
removerecords: 'onStoreRemove',
updaterecord: 'onStoreUpdate'
}
However it would probably be tedious work perfecting it.
On the other hand, your DOM shouldn't be refreshed for the other lists when adding a new record, it should only add a new list item to each list so disabling the addrecords event and then doing a complete refresh of the other lists when they are displayed will probably be more ineffective?
I know this question was already posted in StackOverflow but I either didnt understand or sencha changed somewhat.
My app loads a form panel for login, then I would like to save the user info that have just loged on. This way I can change my view anytime I want and still know the name of the loged in user.
Here is my main code:
//<debug>
Ext.Loader.setPath({
'Ext': 'sdk/src'
});
//</debug>
Ext.application({
name: 'APP',
loadedUser: 'the test',
requires: ['Ext.MessageBox'],
views: ['Main', 'Home', 'Login'],
models: ['User'],
stores: ['Users'],
controllers: ['Main'],
icon: {
57: 'resources/icons/Icon.png',
72: 'resources/icons/Icon~ipad.png',
114: 'resources/icons/Icon#2x.png',
144: 'resources/icons/Icon~ipad#2x.png'
},
phoneStartupScreen: 'resources/loading/Homescreen.jpg',
tabletStartupScreen: 'resources/loading/Homescreen~ipad.jpg',
setLoadedUser: function(arg) {
this.loadedUser = arg;
},
launch: function() {
// Destroy the #appLoadingIndicator element
Ext.fly('appLoadingIndicator').destroy();
// Initialize the main view
Ext.Viewport.add(Ext.create('APP.view.Main'));
},
onUpdated: function() {
Ext.Msg.confirm("Application Update", "This application has just successfully been updated to the latest version. Reload now?", function() {
window.location.reload();
});
}
});
The 'loadedUser' its what I wanted to be my global variable, and the method setLoadedUser(arg) its suposed to change that value.
I can access 'loadedUser' no problem, but I can't change its value.
Another question: loadedUser can it be an array/data structure?
How are you accessing the function? This works for me. Remember you should access it like this:
APP.app.setLoadedUser('test');
And yes, it can be any value. :)
You can also use localStorage to, set/get Your variables:
Set it as:
localStorage.setItem('currentUserId', userID)
Get it as:
localStorage.getItem('currentUserId')
You can use it, anywhere in Your script.
Yes, the works when the function is inside of the app.js file.
It does not work if the function is inside of the controller file.
So if you have a project application called IronMan, the call from the view code to the global function, flyAway(), in your app.js file would look like:
IronMan.app.flyAway();