Binding Variable to Custom HTML or Label Component

Posted by jts-law on 06-Jul-2017 08:36

I have a calculated value that I want to display on a view, how do I bind a component to a variable (stand alone variable, not part of a model)?  As long as the data is read only on the page I think I should be able to use a label, custom html component, or whatever.

TIA,

Louis

Posted by egarcia on 11-Jul-2017 16:02

Hello Louis,

Yes, it might be a timing issue. The "then()" might be executing after the HTML has been initialized and setting options.html is too late.

(What do you see in the message from the console.log()?)

Perhaps, you could set the custom HTML component directly instead of setting it via the options.

Here is a sample "setInitialHTML()" function that uses $watch() to watch for when the component is instantiated and then set the component.

    setInitialHTML(componentName, htmlText) {
		var cancelWatch = this.$scope.$watch(function() {
			var element = angular.element(componentName);
			if (element.html() === undefined) {
				return undefined;
			} else {
				return element;
			}
		},function(element, oldValue) {  
			if (element) {
				element.html(htmlText);
				cancelWatch();
			}
		});		
	}
	
    // Fired when view content is loaded
    onShow($scope) {
        console.log('Show: ' + this);
        this.setInitialHTML("#customhtml0", "Hello World!");		
    }

I hope this helps,

Edsel

All Replies

Posted by egarcia on 10-Jul-2017 13:20

Hello Louis,

Here is a possible approach.

If your component is defined in a custom section, for example, in topSection.html, you can define specify the ng-model property for the component so that it points to a property in the scope.

Example:

<div>Custom HTML: {{testVariable}}</div>

<input ng-model="testVariable">

<br>

IF you have defined the component via the designer (custom view using the blank view option), then you could set ng-model dynamically using the following code:

function setNgModel($scope, componentName, variableName) {
    var cancelWatch = $scope.$watch(function() {
        var element = angular.element("#" + componentName);
        return element.length === 0 ? undefined : element; 
    }, function(element, oldValue) {
        if (element) {				
            element.attr("ng-model-options", "{ updateOn: 'default blur', debounce: { 'default': 500, 'blur': 0 }}");
            element.attr("ng-model", variableName);						
            $compile(element)($scope);
            cancelWatch();							

        }
    });				
}

This code sets ng-model and ng-model-options on the specified component.

You can call the setNgModel() function from the onShow() handler.

Example:

setNgModel($scope, "textbox0", "testVariable");

You can then set "testVariable" in the scope dynamically.

Example:

onRowSelect: function(e) {
    var selectedRows = e.sender.select();
    var dataItem = e.sender.dataItem(selectedRows[0]);
    this.scope.testVariable = dataItem.Name;
}

You could place setNgModel() in your own library so that you can reuse the code and enhance/change it when you need to.

I hope this helps,

Edsel

Posted by jts-law on 10-Jul-2017 15:08

Edsel,

I tried this approach and can't get it to work.  Since my data changes based on a dropdown on the landing page, I decided to not try to bind the variable and instead simply try to populate the custom HTML element.  I can't get this to work either.

Also, I should have mentioned that I'm using KUIB 2.0.0.75.

This is what I have so far:

In KUIB, I have a blank view with a Custom HTML component.

The Id is "lblLookupsCurrentDB" and the HTML is "<span class="DB-Label"></span>"

In my controller constructor (in controller.public.js) I have the following:

       this.domainService.getCurrentDomain().then(() => {

           console.log('[ParametersLookupsCtrl] Current domain: ' + this.domainService.currentName);

           this.$components.lblLookupsCurrentDB.options.html = this.domainService.currentName;

       });

The landing page has a dropdown that sets the domain via the domainService service.  If I start on the landing page, when I go to the page with the above code, it works fine.  My issue is when I start on this page (or refresh the browser on this page), my text doesn't display.  If I start on this page, go to any other page, then go back to this page it then displays.  I think it's a timing issue because the call to getCurrentDomain() performs an $http get so the value isn't set immediately.

It seems like I should be able to bind them so I could go back to trying this as well. I'll take anything that will make it work.

Thoughts?

Louis

Posted by egarcia on 11-Jul-2017 16:02

Hello Louis,

Yes, it might be a timing issue. The "then()" might be executing after the HTML has been initialized and setting options.html is too late.

(What do you see in the message from the console.log()?)

Perhaps, you could set the custom HTML component directly instead of setting it via the options.

Here is a sample "setInitialHTML()" function that uses $watch() to watch for when the component is instantiated and then set the component.

    setInitialHTML(componentName, htmlText) {
		var cancelWatch = this.$scope.$watch(function() {
			var element = angular.element(componentName);
			if (element.html() === undefined) {
				return undefined;
			} else {
				return element;
			}
		},function(element, oldValue) {  
			if (element) {
				element.html(htmlText);
				cancelWatch();
			}
		});		
	}
	
    // Fired when view content is loaded
    onShow($scope) {
        console.log('Show: ' + this);
        this.setInitialHTML("#customhtml0", "Hello World!");		
    }

I hope this helps,

Edsel

Posted by jts-law on 12-Jul-2017 10:02

Edsel,

That worked.  I still have to wait for the data I want to display to be available (the .then()), so I combined the logic and put your setInitialHTML() in my .then() and everything appears to working correctly.

Also, if you can come up with any examples of binding data using the version 2 structure, that would be great.  I'm going to need this functionality shortly.

Thanks for your help.

Louis

This thread is closed