最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Hiding empty elements on page load, but not afterwards using knockout.js - Stack Overflow

programmeradmin4浏览0评论

I have a form with a lot of inputs.

I am using the following syntax within my form: <!-- ko if: PropertyName -->. I am using this statement in the form for specific fields. This allows me to hide values that are not defined (actually not hide, but remove from DOM).

However, I do not need to hide them on the fly. I mean, when value was not empty and was loaded, then user can edit it, and user can empty it. In this case input disappears, I do not need this.

Can you suggest me – how to change my markup and what binding to use?

<!-- ko if: IsEmptyOnLoad(Property1) -->.
<input type="text" data-bind="value: Property1" />
<!-- /ko -->

<!-- ko if: IsEmptyOnLoad (Property2) -->.
<input type="text" data-bind="value: Property2" />
<!-- /ko -->

var myModel = function() {
    var self = this;

    self.Property1= ko.observable("non-empty");
    self.Property2= ko.observable();

    //self.IsEmptyOnLoad  is not implemented, how to implement?
};

var m = new myModel();
ko.applyBindings(m);

You can try playing with the corresponding JSFiddle.

It could be strange, but I really have business scenario:

  • onload do not show any empty variables, so after page is loaded there would be only non-empty variables loaded into the page
  • after page is loaded, user can edit variables, some of those variables can be removed (bee empty), but in this case I do not need to hide empty variables

I have a form with a lot of inputs.

I am using the following syntax within my form: <!-- ko if: PropertyName -->. I am using this statement in the form for specific fields. This allows me to hide values that are not defined (actually not hide, but remove from DOM).

However, I do not need to hide them on the fly. I mean, when value was not empty and was loaded, then user can edit it, and user can empty it. In this case input disappears, I do not need this.

Can you suggest me – how to change my markup and what binding to use?

<!-- ko if: IsEmptyOnLoad(Property1) -->.
<input type="text" data-bind="value: Property1" />
<!-- /ko -->

<!-- ko if: IsEmptyOnLoad (Property2) -->.
<input type="text" data-bind="value: Property2" />
<!-- /ko -->

var myModel = function() {
    var self = this;

    self.Property1= ko.observable("non-empty");
    self.Property2= ko.observable();

    //self.IsEmptyOnLoad  is not implemented, how to implement?
};

var m = new myModel();
ko.applyBindings(m);

You can try playing with the corresponding JSFiddle.

It could be strange, but I really have business scenario:

  • onload do not show any empty variables, so after page is loaded there would be only non-empty variables loaded into the page
  • after page is loaded, user can edit variables, some of those variables can be removed (bee empty), but in this case I do not need to hide empty variables
Share Improve this question edited Dec 16, 2013 at 0:43 Palec 13.6k8 gold badges76 silver badges142 bronze badges asked Dec 6, 2013 at 13:22 renathyrenathy 5,36520 gold badges92 silver badges155 bronze badges 7
  • I usually simply hide the div containing the bound UI items and showing some kind of "is loading..." instead. – Rob Commented Dec 6, 2013 at 13:26
  • Please create a fiddle. As it stands this is extremely easy to acplish multiple ways and should be trivial to do... – PW Kad Commented Dec 6, 2013 at 13:30
  • jsfiddle/2FTEM – renathy Commented Dec 6, 2013 at 13:36
  • It is not related to "is loading". – renathy Commented Dec 6, 2013 at 14:19
  • 2 Awwh, you've let the bounty slide. Though I was under the impression that you have some good answers here. What do you miss? – flup Commented Dec 17, 2013 at 14:28
 |  Show 2 more ments

5 Answers 5

Reset to default 1

Just create custom binding with empty update method. You can do whatever you want at binding init on page load (at knockout binding apply to be more specific).

ko.bindingHandlers.ifOnce = {
    init: function(element, valueAccessor) {
        var observable = valueAccessor(); // get observable
        var value = observable(); // get value of observable
        var isEmpty = !value; // do whatever check you want
        // and remove element from dom if empty
        if (isEmpty) {
            element.parentNode.removeChild(element);
        }
    },
    update: function(element, valueAccessor) {
        // do nothing on update
    }
};

Working example: http://jsfiddle/2FTEM/6/

Lets go one step further. You asked how to create IsEmptyOnLoad. You can do this by using Knockout virtual elements and some useful methods they have. I.e.: ko.virtualElements.emptyNode will remove everything between Knockout <!-- ko --> tags http://knockoutjs./documentation/custom-bindings-for-virtual-elements.html

ko.bindingHandlers.IsEmptyOnLoad = {
    init: function(element, valueAccessor) {
        var observable = valueAccessor(); // get observable
        var value = observable(); // get value of observable
        var isEmpty = !value; // do whatever check you want
        // and remove element from dom if empty
        if (isEmpty) {
            ko.virtualElements.emptyNode(element);
        }
    },
    update: function(element, valueAccessor) {
        // do nothing on update
    }
};
ko.virtualElements.allowedBindings.IsEmptyOnLoad = true;

Working example: http://jsfiddle/2FTEM/7/

An interesting problem that has so far generated some inventive answers. It's a mon trend that people seem to have a phobia of putting logic into the view-model. As the name suggests, it should be designed as an interface between the view and the model. Firstly, I would re-factor the view-model, something like this;

var myModel = function() {
    var self = this;
    var property = function (content, availibility) {
        return { 
            content: ko.observable(content),
            availibility: availibility
       };
    }
    self.Property1 = property('non-empty', true);
    self.Property2 = property();
};

Now your HTML can be simple;

<input type="text" data-bind="visible: Property1.availibility, value: Property1.content" />
<input type="text" data-bind="visible: Property2.availibility, value: Property2.content" />

I've also provided a fork of the JSFiddle for your reference

UPDATE: Re-factored for simplicity and minimal repetition.

Do you simply want to disable the additional field if the FirstName is empty? I can't see how hiding the first input field, as you are currently doing, will work as it will not allow anyone to enter a name once it disappears.

If you want to disable additional fields and leave the first filed you can use data-bind with disable to do the following and remove your <!-- ko if: .... --> statements:

<input type="text" data-bind="value: FirstName" />

<input type="text" data-bind="disable: FirstName().length === 0" />

See updated fiddle: http://jsfiddle/2FTEM/1/

UPDATE

You can set up an observable that updates once your view model is loaded: IsPageLoaded that you set to true. I've added a delay in the JS so you should see the control appear after the final lines update the observable: m.IsPageLoaded(true);. You may have to check this with your code to see if it works (without the setTimeout).

HTML:

<!-- ko if: IsNotEmpty -->.
<input type="text" data-bind="value: IsNotEmpty" />
<!-- /ko --> 

<!-- ko if: IsEmpty && IsPageLoaded -->.
<input type="text" data-bind="value: ''" />
<!-- /ko --> 

JS:

var myModel = function() {
  var self = this;
  self.IsPageLoaded = ko.observable(false);

  self.IsNotEmpty = ko.observable("non-empty");
  self.IsEmpty = ko.observable(true);

};

var m = new myModel();
ko.applyBindings(m);

// remove this timeout to test in your enviroment - just introduces a delay
setTimeout(function() {
    m.IsPageLoaded(true);
}, 1000);

// simply use
// m.IsPageLoaded(true);

Updated Fiddle: http://jsfiddle/2FTEM/4/

Keep two copies of your model around: the version as it was on load and the version that's currently being edited.

var m = { onload : new myModel(), 
          current : new myModel() };
ko.applyBindings(m);

When binding, bind the visibility to the state on load and the editable value to the current state:

<!-- ko if: onload.Property1 -->.
<input type="text" 
    data-bind="value: current.Property1" />
<!-- /ko -->

http://jsfiddle/92GzK/

You can create normal variables (instead of observables) that are only used in the "if" statements. This way, the condition within the "if" won't get updated if you update the field :

self.Property1 = ko.observable("non-empty");
self.Property2 = ko.observable();

self.initialValue1 = self.Property1();
self.initialValue2 = self.Property2();

and the bindings are :

<!-- ko if: initialValue1 -->.
<input type="text" data-bind="value: Property1" />
<!-- /ko -->
<!-- ko if: initialValue2 -->.
<input type="text" data-bind="value: Property2" />
<!-- /ko -->

fiddle here : http://jsfiddle/2FTEM/13/ Hope that helps

发布评论

评论列表(0)

  1. 暂无评论