1. #1
    Sencha User
    Join Date
    Mar 2010
    Location
    Laguna Niguel, CA
    Posts
    62
    Vote Rating
    0
    jeetmarwah is on a distinguished road

      0  

    Default Answered: Issue with reusing the SplitButton on multiple tabs

    Answered: Issue with reusing the SplitButton on multiple tabs


    I have a menu that I want to show in multiple tabs. For that I created this class so that I can reuse it.

    Code:
    Ext.define('RS.view.common.RSSplitButton', {
        extend : 'Ext.button.Split',
        alias: 'widget.rssplitbutton',
        id : 'rssplitbuttonId',
    	text : 'Menu',
    	menu : new Ext.menu.Menu({
    			items : [
    				{
    					text: 'Add To Home',
    					//checked: true,       // when checked has a boolean value, it is assumed to be a CheckItem
    					handler: function() {console.log('Add is clicked');}
    				},
    				{
    					text: 'Remove from Home',
    					handler: function() {console.log('Remove is clicked');}
    				}
    			]												
    	})//end of menu
    });
    And here is the snippet to the code that I have on 2 different panels which are on the tab.

    Code:
    Ext.define('RS.view.AdvanceTabPanel', {
        extend : 'Ext.panel.Panel',
        alias: 'widget.advancetabpanel',
    	
    	requires: ['RS.view.common.RSSplitButton', 'RS.view.Streams',  'RS.view.PostDisplay'],
    	 
        id : 'advancetabpanelId',
    	border : false,
    	dockedItems: [{
    		xtype: 'toolbar',
    		id: 'advancetoolbarid',
    		dock: 'top',
    		items : [
    			{
    				xtype : 'label',
    				html: '<font size="2"><b>Streams</b></font>'
    			},
    			'->', //for right align
    			{
    				xtype: 'rssplitbutton',
    				id : 'rssplitbuttonId_ap'
    			}
    		]
    	}],
    .....
    I get the following error when I am running this code.

    Code:
    el is null
    a2 = el.getAnchorXY(p2, false);
    error.jpg



    Any clue anybody ??

  2. Static ids are trouble. I strongly recommend getting rid of them. Even if they aren't causing this problem they will cause you a problem at some point down the line.

    This looks problematic too:

    Code:
    Ext.define('RS.view.common.RSSplitButton', {
        ...
        menu : new Ext.menu.Menu({
            items: [
                {...}, {...}
            ]
        })
    });
    You're storing the menu on the prototype of your class. The result will be that the same menu instance is shared between all instances of your class. I gave this a quick try myself and while I didn't see exactly the same error you're experiencing it did cause other problems.

    Try this instead:

    Code:
    Ext.define('RS.view.common.RSSplitButton', {
        ...
        menu: [
            {...}, {...}
        ]
    });
    This puts a menu items config on the prototype instead, so that each button gets its own menu.

  3. #2
    Sencha Premium Member skirtle's Avatar
    Join Date
    Oct 2010
    Location
    UK
    Posts
    3,605
    Answers
    543
    Vote Rating
    326
    skirtle has a brilliant future skirtle has a brilliant future skirtle has a brilliant future skirtle has a brilliant future skirtle has a brilliant future skirtle has a brilliant future skirtle has a brilliant future skirtle has a brilliant future skirtle has a brilliant future skirtle has a brilliant future skirtle has a brilliant future

      1  

    Default


    Static ids are trouble. I strongly recommend getting rid of them. Even if they aren't causing this problem they will cause you a problem at some point down the line.

    This looks problematic too:

    Code:
    Ext.define('RS.view.common.RSSplitButton', {
        ...
        menu : new Ext.menu.Menu({
            items: [
                {...}, {...}
            ]
        })
    });
    You're storing the menu on the prototype of your class. The result will be that the same menu instance is shared between all instances of your class. I gave this a quick try myself and while I didn't see exactly the same error you're experiencing it did cause other problems.

    Try this instead:

    Code:
    Ext.define('RS.view.common.RSSplitButton', {
        ...
        menu: [
            {...}, {...}
        ]
    });
    This puts a menu items config on the prototype instead, so that each button gets its own menu.

  4. #3
    Sencha User
    Join Date
    Mar 2010
    Location
    Laguna Niguel, CA
    Posts
    62
    Vote Rating
    0
    jeetmarwah is on a distinguished road

      0  

    Default


    skirtle,

    Thanks a lot for your answer and suggestion. The UI rendered correctly after I made the changes you mentioned.

    I know that ids create a lot of issues but I am still a beginner in extjs/js world. I am still trying to understand how to use inheritance/resuablity using extjs. Like for eg, I want to share the same XTemplate on the different tabs that I have and I don't know how to do it. So I end up duplicating it for each tab. Here is the code that I have to duplicate all over. Please let me know if you have any suggestions on this one. Note that I have to change the 'ids' for each tab which again I think is not right but that's the only way I know right now.

    Code:
    var commentTpl = new Ext.Template
    (
    	'<div class="feeditemcomment cxfeedcomment " style="display:block">',
    		'<span class="feeditemcommentbody">',
    			'<span class="feedcommentuser"><a href="/00550000001qcWu" class="actorentitylink">{author}</a></span>',
    			'<span style="float:right;color: #909090;">{date}</span><br/><br/>',							
    			'<span class="feedcommenttext">{comment}</span><br/><br/>',
    			'<span class="feedcommentfooter"></span>',
    		'</span>',
    	'</div>'
    );
    
    
    var postTpl = new Ext.XTemplate
    (
    	'<tpl for=".">',
    		'<div id="{sys_id}" class="feedcontainer actionsOnHoverEnabled cxfeedcontainer">',
    			'<div class="cxfeeditem feeditem">',
    				'<span class="feeddata cxfeeditemid" style="display:none">0D55000000FckWE</span>',
    				'<span class="cxfeeditemparentid feeddata" style="display:none">0F9500000000232</span>',
    				'<span class="cxfeeditemparentname feeddata" style="display:none">Chatter Group</span>',
    				'<span class="cxfeeditemparentname feeddata" style="display:none">{sys_id}</span>',
    				'<span class="cxfeeditemparentname feeddata" style="display:none">{posttype}</span>',
    				'<div class="feeditemcontent cxfeeditemcontent">',
    					'<div class="feeditembody">',
    						'<a href="/0F9500000000232" class="feeditemfirstentity">{targetentity}</a> — ',
    						'<span  class="feeditemsecondentity">',
    							'<a href="/00550000001qNTE" class="actorentitylink">{postauthor}</a>',
    							'<span style="float:right;color: #909090;">{postdate}</span>',
    						'</span>',
    						'<br/><br/>',
    						'<span class="feeditemtext">{postcontent}</span>',
    					'</div>',
    					'<div class="feeditemextras">',
    						'<div class="cxfeedcommentarrow feedcommentarrow"></div>',
    						'<div class="cxcomments feeditemcomments">',
    							'<div class="cxlikecontainer" style="display:none"></div>',
    							'<div class="cxfeedcommentsshowmore feedcommentsshowmore" style="display:block">',
    								'<div class="cxshowmorecommentscontainer showmorecommentscontainer">',
    									'<span  class="cxshowmorecommentslabel">Comments</span>',
    								'</div>',
    							'</div>',
    							'<div id={[this.getAllCommentsId(values)]}>',
    								'<tpl for="comments">',
    								'{[ this.renderComments(values) ]}',
    								'</tpl>',
    							'</div>',
    						'</div>',
    					'</div>',
    				'</div>',
    			'</div>',
    		'</div>',
    	'</tpl>',
    	{
    		renderComments: function(values) {
    			console.log('values for comment --' + values.toString());
    			var comm = commentTpl.apply(values);
    			//console.log(comm);
    			return comm;
    		},
    		getAllCommentsId: function(values) {
    			var id = 'hp_allcomments_' + values.sys_id;
    			return id;
    		},
    		getLinkId: function(values) {
    			var linkId = Ext.id() + '||' + values.sys_id;// + '||' +  values.targetentity.replace(/\s+/g, "~")  + '~-~' +  values.postauthor.replace(/\s+/g, "~");
    			Ext.Function.defer(this.addOnClickForComment, 1000, this, [linkId]);
    			return linkId;
    		},
    		getLikeLinkId: function(values) {
    			var linkId = Ext.id();
    			Ext.Function.defer(this.addOnClickForLike, 1000, this, [linkId]);
    			return linkId;
    		},
    		getCommentBtnId: function(values) {
    			var id = Ext.id() + '||' + values.sys_id ;
    			Ext.Function.defer(this.addBtnOnClickForComment, 1000, this, [id]);
    			return id;
    		},
    		getTADivId: function(values) {
    			var id = "hp_divta_" + values.sys_id;
    			Ext.Function.defer(this.addKeyEventsToTextArea, 1000, this, [id]);
    			return id;
    		},
    		getTAId: function(values) {
    			var id = "hp_ta_" + values.sys_id;
    			return id;
    		},
    		showCommentTA: function(eventObj, htmlElementObj) {
    			eventObj.stopEvent(); 
    			if(htmlElementObj.id)
    			{
    				var valueStr = htmlElementObj.id.split("||");
    				var postId = valueStr[1];
    				Ext.get("hp_divta_" + postId).show();
    			}
    			cleanForm();//**js for textarea -- in the textareaResizer.js file
    				
    		},
    		showLike: function(eventObj, htmlElementObj) {
    			eventObj.stopEvent(); 
    			Ext.Msg.alert("Alert", "Coming Soon...");
    		},
    		addOnClickForComment: function(id) {
    			console.log('id for comment -- ' + id);
    			//Ext.get(id).on('click', this.commentOnClick)
    			var element = Ext.get(id);
    			if(element)
    			{
    				element.on('click', this.showCommentTA);
    			}
    		},
    		addOnClickForLike: function(id) {
    			console.log('id for like -- ' + id);
    			var element = Ext.get(id);
    			if(element)
    			{
    				element.on('click', this.showLike);
    			}	
    		},
    		addBtnOnClickForComment: function(id) {
    			var element = Ext.get(id);
    			if(element)
    			{
    				Ext.get(id).on('click', this.submitComment);
    			}
    		},
    		addKeyEventsToTextArea: function(id)  {
    			//textarea was not allowing to the 'spacebar'. To solve this issue, I have to stop all the key events to propagate
    			var element = Ext.get(id);
    			if(element)
    			{
    				element.on('keydown', this.stopEventsForTextArea);// IE, Chrome ans Safari
    				element.on('keypress', this.stopEventsForTextArea);//// FF and Opera
    			}
    		},
    		stopEventsForTextArea: function(eventObj, htmlElementObj) {
    			eventObj.stopPropagation();
    		},
    		submitComment: function(eventObj, htmlElementObj) {
    			eventObj.stopEvent(); 
    
    
    			console.log('button ' + htmlElementObj.id + ' clicked');
    			var valueStr = htmlElementObj.id.split("||");
    			var postId = valueStr[1];
    			var comment = Ext.get("hp_ta_" + postId);
    			var commentValue = comment.getValue();
    			console.log('comment -- ' + commentValue);
    			
    			Ext.Ajax.request({
    				url: '/resolve/service/submitComment',
    				params: {
    					postId: postId,
    					comment: commentValue
    				},
    				success: function(response){
    					var text = response.responseText;
    					var jsonObj = Ext.JSON.decode(text);
    					var postId = jsonObj.postId;
    					var commentObj = jsonObj.comment;
    					
    					var newComment = commentTpl.applyTemplate(commentObj);
    					//var newCommentEl = new Ext.Element(newComment);
    					//Ext.get('hp_allcomments_' + postId).insertFirst(newCommentEl);
    					Ext.get('hp_allcomments_' + postId).insertHtml('beforeEnd', newComment);
    				}
    			});
    		},
    		test: function(){
    			this.callParent();
    		},
    		/*addOnClickForComment: function(id) {
    			Ext.get(id).on('click', function(eventObj, htmlElementObj){
    				eventObj.stopEvent(); 
    				alert('link ' + htmlElementObj.id + ' clicked');
    			})
    		},*/
    		commentOnClick: function (eventObj, htmlElementObj) {
    			eventObj.stopEvent(); 
    			//alert('link ' + htmlElementObj.id + ' clicked');
    			if(htmlElementObj.id)
    			{
    				var valueStr = htmlElementObj.id.split("||");
    				var postId = valueStr[1];
    				var postHeading = valueStr[2].replace(/~/g, " ");//replace ~ with space
    				console.log('postId comment -- ' + postId);
    				console.log('postHeading comment -- ' + postHeading);
    				var commentModel =  Ext.create('RS.model.CommentM', {
    					comment:'',
    					postheading: postHeading,
    					postid : postId
    				});
    				var addcomment = Ext.widget('addcomment');
    				addcomment.down('form').loadRecord(commentModel);
    			}
    		}
    	}
    );
    
    
    
    
    Ext.define('RS.view.HomePostPanel', {
        //extend: 'Ext.view.View',
    	extend: 'Ext.grid.Panel',
        alias: 'widget.homepostpanel',    
        store: 'HomePostsStore',
    	autoScroll :true,
    	border : false,
    	loadMask: true,
        disableSelection: true,
    	hideHeaders : true,
    	
    	/*for infinite scrolling - THIS DOES NOT WORK*/
    	/*
    	verticalScrollerType: 'paginggridscroller',
    	invalidateScrollerOnRefresh: false,
    	viewConfig: {
            trackOver: false
        },
    		*/
        //itemTpl: postTpl//'<div>homepostpanel --> {name}</div><br/><br/><br/><br/><br/><br/><br/>'
    	columns: [
    		{
                xtype: 'rownumberer',
                width: 50,
                sortable: false
            },
    		{xtype: 'templatecolumn', tpl: postTpl, flex: 1 }
    	]
    	,//THIS WORKS
    	dockedItems: [{
            xtype: 'pagingtoolbar',
            store: 'HomePostsStore',   // same store GridPanel is using
            dock: 'bottom',
            displayInfo: true,
    		listeners: {
    			beforeload: {
    				fn: function(){ console.log('click el -------------------------'); }
    			}
    		}
        }]
    });
    Last edited by skirtle; 20 Jan 2012 at 7:10 PM. Reason: Remove tags to make the post easier to read

  5. #4
    Sencha Premium Member skirtle's Avatar
    Join Date
    Oct 2010
    Location
    UK
    Posts
    3,605
    Answers
    543
    Vote Rating
    326
    skirtle has a brilliant future skirtle has a brilliant future skirtle has a brilliant future skirtle has a brilliant future skirtle has a brilliant future skirtle has a brilliant future skirtle has a brilliant future skirtle has a brilliant future skirtle has a brilliant future skirtle has a brilliant future skirtle has a brilliant future

      0  

    Default


    I don't entirely understand the question. I suggest posting it as a separate question, you'll get more people reading it that way. I'd also advise posting much shorter code examples, nobody will read your code if you post that much. Try to extract the essence of the code rather than just posting it as-is. For example, do you really need to post all of those methods or would 2 or 3 demonstrate the principle just as well?

    The simplest way to share a template is just to create it as a singleton instance:

    Code:
    Ext.ns('Namespace.tpl');
    
    Namespace.tpl.MyTemplate = new Ext.XTemplate(...);
    You'd then put that in a separate file and treat it just like any other 'class'. There are other ways to do it but for such a large template I think this is the way I'd go.

    One thought that did occur to me as I skimmed over your template. It looks like you might be over-complicating the event handling by trying to register listeners directly on individual elements. DOM events propagate, so you can catch them on the root element rather than on the actual target element. A bit of event delegation might simplify your code. See the section on delegate here:

    http://docs.sencha.com/ext-js/4-0/#!...ment-method-on

  6. #5
    Sencha User
    Join Date
    Mar 2010
    Location
    Laguna Niguel, CA
    Posts
    62
    Vote Rating
    0
    jeetmarwah is on a distinguished road

      0  

    Default


    PM
    skirtle,

    Thanks a lot again. I deeply appreciate it.

    I understand what you are trying to explain about events and you are right that its an overhead but that is the only way I know right now. I read the link that you had put in for the Element.on , but my javascript skill is not at par to know how to do it yet. Hopefully, I will understand and apply it in few months time.

    Please feel free to suggest me as you and all the people in this forum are my gurus/teachers.

    Thanks again,

    Jeet

Thread Participants: 1