根据控制器响应动态更改视图部分

Posted

技术标签:

【中文标题】根据控制器响应动态更改视图部分【英文标题】:Changing parts of view dynamically based on controller response 【发布时间】:2017-06-03 23:51:50 【问题描述】:

我正在寻找以下场景的最佳方法建议:

用户可以选择一个或多个 csv 文件进行验证(附件 1),单击“验证”按钮会检查验证代码(在返回输出之前显示进度条)。 返回响应可以是成功消息,也可以是选择验证的每个文件的错误详细信息(附件 2) 现在可以使用“上传”按钮将成功验证的文件上传到 Azure 存储。

附件 1

附件 2

现在,为了使所有内容异步,我的想法是视图需要为每个文件提供单独的灵活部分。

我正在使用带有 knockout.js 的 MVC5 剃须刀视图,我对部分视图有很好的想法,但我不确定如何去做。如果不是局部视图,那么最好的方法是什么。

【问题讨论】:

您是否在一个请求中上传所有文件?? 每个成功验证的文件都有一个“上传”按钮。一次只能使用一个请求上传。 你检查了吗:***.com/questions/24545780/… 这确实有帮助,但我主要关心的是如何在保持相同模型和控制器的同时实现每个文件的 UI、显示/隐藏按钮、消息。 您可以有一个显示文件名的通用视图页面,如果正在上传,则显示剩余时间,否则显示上传按钮或验证消息。使用单个局部视图并从控制器填充值 【参考方案1】:

我的想法是视图需要有单独的灵活部分 每个文件

有点,我认为您需要一个单独的文件模型/类,以便按需运行 ajax 命令,至少我是这样理解您的解释的。

查看这个 jsfiddle,我添加了一些随机的真/假和字符串内容,以尝试尽快模仿您的布局。对于测试,请尝试使用 5 个或更多文件(随机生成器在 JS 中有点挑剔)。

https://jsfiddle.net/n2ne6yLh/10/

所以基本上你在文件输入上监听一个更改事件。在这种情况下,将每个文件映射到一个新模型“FileModel”,然后将其推送到 observableArray 文件中。每个 FileModel 都包含它自己的单独结果、验证功能等。然后布局负责其余的工作。

您需要查看 FormData Web API 才能使用 javascript 处理文件。如果您的客户/用户正在使用过时的浏览器,那么 FormData 的东西、jquery 和你有什么的 shims/polyfills。 https://developer.mozilla.org/en-US/docs/Web/API/FormData

var PageModel = function(r) 
  var self = this;
  this.Files = ko.observableArray();
  this.FileErrors = ko.computed(function() 
    return _.some(self.Files(), function(file) 
      return file.IsValid() === false;
    );
  );
  this.ClearFiles = function() 
    document.getElementById("your-files").value = "";
    self.Files([]);
  ;

  var control = document.getElementById("your-files");
  control.addEventListener("change", function(event) 
    // When the control has changed, there are new files
    var i = 0,
      files = control.files,
      len = files.length;
    var form = new FormData();

    for (; i < len; i++) 
      form.append(files[i].name, files[i]);
      self.Files.push(new FileModel(files[i], files[i]));
    
  , false);



var FileModel = function(r, fileObject) 
  var self = this;
  this.FileObject = fileObject;
  this.Name = r.name;
  this.Type = r.type;
  this.Size = r.size;

  this.IsValidated = ko.observable(false);
  this.IsValid = ko.observable();
  this.ValidationErrors = ko.observable();

  this.ValidateFile = function() 
    //Do some ajax to validate file
    //console.log('Doing an ajax thing.')

    // Randomizers for validation, remove in production
    var random_boolean = Math.random() >= 0.5;
    var random_strins = Math.random().toString(36).substring(7);

    // Set vals based on returned ajax response.
    self.IsValidated(true);
    self.IsValid(random_boolean);
    self.ValidationErrors(random_strins);
  ;
  this.UploadFile = function() 
    alert('uploading this file to the interwebs, yay!')
  


window.model = new PageModel();
ko.applyBindings(model);
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<div class="container">
  <div class="row">
    <div class="col-md-6 col-md-push-3">
      <div class="form-group">
        <div class="input-group">
          <input type="file" class="form-control" id="your-files" multiple>
          <span class="input-group-btn">
    <button class="btn btn-info" data-bind="click: ClearFiles">Clear</button>
  </span>
        </div>
      </div>
    </div>
  </div>
</div>

<div class="container-fluid">
  <div class="row">
    <div class="col-sm-6">
      <h4>Validate Files</h4>
      <!-- ko if: Files().length > 0 -->
      <table class="table table-condensed table-hover">
        <thead>
          <tr>
            <th>Name</th>
            <th>Type</th>
            <th>Size (bytes)</th>
          </tr>
        </thead>
        <tbody>
          <!-- ko foreach: Files -->
          <tr data-bind="css: IsValid() ? 'success' : ''">
            <td><span data-bind="text: Name"></span>
            </td>
            <td><span data-bind="text: Type"></span>
            </td>
            <td><span data-bind="text: Size"></span>
            </td>
            <td>
              <button class="btn btn-sm btn-success" data-bind="click: ValidateFile, visible: !IsValidated()">Validate</button>
              <button class="btn btn-sm btn-success" data-bind="click: UploadFile, visible: IsValid()">Upload</button>
            </td>
          </tr>
          <!-- /ko -->
        </tbody>
      </table>
      <!-- /ko -->
    </div>
    <div class="col-sm-6">
      <h4>File Errors</h4>
      <!-- ko if: FileErrors() -->
      <table class="table table-hovered">
        <thead>
          <tr>
            <th>Name</th>
            <th>Error Message</th>
          </tr>
        </thead>
        <tbody>
          <!-- ko foreach: Files -->
          <!-- ko if: IsValid() == false -->
          <tr>
            <td data-bind="text: Name"></td>
            <td data-bind="text: ValidationErrors"></td>
          </tr>
          <!-- /ko -->
          <!-- /ko -->
        </tbody>
      </table>
      <!-- /ko -->
    </div>
  </div>
</div>

【讨论】:

谢谢!这确实符合我的预期,尽管我正在寻找一种使用局部视图的纯剃刀方法。我自己更像是一个 Angular js 人。如果 razor 中没有出现问题,我会接受这个作为最终答案。非常感谢。【参考方案2】:

下面的简单算法怎么样 假设在您的 html 中有一个

您可以在主视图文件中编写以下内容

 function validateFiles(filesToValidate)) 
    foreach(file in filesToValidate)
    
        var fileDivWithIdTheNameOfTheFile = @Html.RenderPartial("A_View_WithProgressBar",file)  
        allFiles.AddElement(fileDivWithIdTheNameOfTheFile );
        ajax.Get("YourActionThatReturnsAResultView",file)
            .OnSuccess(args)
            
                FindDivForCurrentFile.ReplaceWith(args.ResultView)
            

     

这样你的大部分代码都在服务器端,你只需要一些 jquery 代码来在文件验证完成后替换部分页面

【讨论】:

【参考方案3】:

使用局部视图会起作用。只需要一个带有基本表格布局的局部视图即可满足您的需求。然后有

<div id='partial'/>

在隐藏的主窗体中。使用敲除或 jquery 将您的文件发布到您的上传操作。让动作返回您的局部视图。然后使用敲除或 jquery 的成功回调,做这样的事情:

success: function(data) 
             $('#partial').html(data);
          

插入部分视图的 html

【讨论】:

以上是关于根据控制器响应动态更改视图部分的主要内容,如果未能解决你的问题,请参考以下文章

PageMenu 如何动态(以编程方式)添加视图控制器?

动态改变 UITableView 高度

动态更改详细视图控制器

部分视图与 Json(或两者)

如何使用界面生成器动态更改视图控制器的类

根据包含的文本更改 textView 高度